feat: the crafter-review skeleton, and its semantics for text, JSON and crypto
What the rest of crafter-review stands on.
- project.cpp: a static crafter.review-lib and the crafter-review
executable; Crafter.Network without QUIC, pinned, or with --local from
the checkout next to this one; Crafter.LintRules' lite rules, pinned;
the version from CRAFTER_REVIEW_VERSION, git describe or 0.0.0-dev.
- :Core and :Driver: the version, PromptVersion 1, --version.
- :Json: nlohmann's ordered_json, which keeps key order and unknown keys,
so the files every driver on a machine shares survive a rewrite; dumps
in the indented file layout, the spaced one-line form and the compact
sorted form the structured-output schema needs byte for byte.
- :Crypto: SHA-256/SHA-1/MD5, HMAC, PBKDF2 through libcrypto; base64 and
base32 written out, because what they refuse, and with which message,
is pinned.
- :Unicode, Unicode 16.0.0's tables: whitespace, line breaks, decimal
digits, printable characters, case mappings and case-insensitive folds.
- :Text: string functions on code points, number parsing, the shortest
float form and half-even rounding, printed values, shell patterns, URL
splitting and unquoting, POSIX paths, universal newlines and the
replacing UTF-8 decoder.
Tests: Crypto (published vectors), Text (293 reference vectors).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:29:18 +01:00
// SPDX-License-Identifier: AGPL-3.0-only
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
import std ;
import Crafter . Build ;
// Pinned: the Flatpak builds with the base app's crafter-build, which can be
// older than the rules' master. Move the pin together with the base.
# pragma crafter dependency "https: //forgejo.catcrafts.net/Catcrafts/Crafter.LintRules.git" commit "7d932892017800b4e1f1a15fe7aa49b3daee9ceb"
import Crafter . LintRules ;
namespace fs = std : : filesystem ;
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.
feat(pool): the pool - stacks, admission, the runner and the scheduler
The allowlists and the instrument checks (mcp_connected, db_answered,
exercised), the stack keys, Stacks and Admission, the Runner that runs one
claude or opencode process per pass, and the Scheduler with its retries,
rate-window pauses, the prompt-prefix warm-up, the seats and the board.
One thread per pass; each worker runs on its own copy of the job.
Every pass runs under the supervisor, so a timeout or an abort takes its
whole tree down; a timed-out pass reports exit -9, a SIGKILLed child's
code. The helpers the lenses run are this binary's `sql` and `totp`.
:Process gains an Append stream for the OpenCode meta line.
The tests cover the pool and its share of the commits-mode, seat-pool and
several-drivers checks, a fake claude under the supervisor included.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 08:55:00 +01:00
constexpr std : : array < std : : string_view , 30 > Interfaces = {
feat: the crafter-review skeleton, and its semantics for text, JSON and crypto
What the rest of crafter-review stands on.
- project.cpp: a static crafter.review-lib and the crafter-review
executable; Crafter.Network without QUIC, pinned, or with --local from
the checkout next to this one; Crafter.LintRules' lite rules, pinned;
the version from CRAFTER_REVIEW_VERSION, git describe or 0.0.0-dev.
- :Core and :Driver: the version, PromptVersion 1, --version.
- :Json: nlohmann's ordered_json, which keeps key order and unknown keys,
so the files every driver on a machine shares survive a rewrite; dumps
in the indented file layout, the spaced one-line form and the compact
sorted form the structured-output schema needs byte for byte.
- :Crypto: SHA-256/SHA-1/MD5, HMAC, PBKDF2 through libcrypto; base64 and
base32 written out, because what they refuse, and with which message,
is pinned.
- :Unicode, Unicode 16.0.0's tables: whitespace, line breaks, decimal
digits, printable characters, case mappings and case-insensitive folds.
- :Text: string functions on code points, number parsing, the shortest
float form and half-even rounding, printed values, shell patterns, URL
splitting and unquoting, POSIX paths, universal newlines and the
replacing UTF-8 decoder.
Tests: Crypto (published vectors), Text (293 reference vectors).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:29:18 +01:00
" interfaces/Crafter.Review " ,
" interfaces/Crafter.Review-Unicode " ,
" interfaces/Crafter.Review-Json " ,
" interfaces/Crafter.Review-Text " ,
" interfaces/Crafter.Review-Crypto " ,
feat(platform): processes that never outlive their pass, shared files, the board identity
:Process makes sure no child outlives what it was started for. SIGKILL to
the direct child alone would leave the Playwright server and Chromium
running after a timeout, and every pass running after a SIGKILLed driver:
- every child is forked by one long-lived spawner thread, the reaper's
registry locked across fork, so PR_SET_PDEATHSIG holds and a fast exit
is never reaped unregistered; one reaper thread owns waitpid(-1);
- the child gets an empty signal mask, SIGPIPE and SIGXFSZ at their
defaults, and nothing but its three streams (close_range); the driver
ignores SIGPIPE and takes SIGINT/SIGTERM/SIGHUP on a thread of its own;
- `crafter-review __supervise <argv>` is a pass's subreaper. It kills the
pass's whole tree, Chromium's detached process group included, when the
target exits, on SIGTERM, and when the driver dies, by its death signal.
- Run() captures both outputs without the deadlock.
The shared state the detached threads wait on is never destroyed: a
condition variable destroyed under a waiter makes glibc's
pthread_cond_destroy, and with it exit(), wait forever.
:Platform: the Flatpak sandbox decided once, the host's XDG directories
restored there; WriteAtomic and LockedUpdate, the read-modify-write of
the board, ledger, memory.json and unit-state.json every driver on the
machine shares, under flock(2) on the same side files; /proc readers; and
the identity other drivers can check: natively pid and start time, in the
sandbox the instance's host pid from bwrapinfo.json with /proc/1's start
time. The lifetime lock is created under a temporary name and renamed into
place, so no prober ever finds it unlocked while its driver lives.
Tests: Process (the three ways a pass's tree must die, return codes, a
missing program, capture, timeouts, fds, the child's signal state),
Platform (atomic writes, LockedUpdate against a damaged file, two writers,
and another process holding flock on the side file; /proc on a fake
tree; both identities; the lifetime lock; the XDG restore).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:49:46 +01:00
" interfaces/Crafter.Review-Platform " ,
" interfaces/Crafter.Review-Process " ,
feat(seatpool): the seat pool and the board several drivers share
The seats of .env and the ledger, the probe, placement, settling a
finished pass, the child's credentials, the OpenRouter seats, and the
board every driver on the machine shares, in one shape and under one
lock. A driver is alive while its lifetime lock is held; with no lock file
natively its pid and start time decide, and in the sandbox it is taken for
alive.
:Http is the HTTP the driver needs, on FetchHTTP1: a status outside 2xx is
HttpError, every other failure carries a fixed text. :Platform gains
MakeDirs, with the last directory's own mode, and errno texts for its
writes and locks.
The tests cover the seat pool and several drivers at once, less the checks
that drive the pool's Scheduler, Admission and Stacks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 08:15:03 +01:00
" interfaces/Crafter.Review-Http " ,
feat: the crafter-review skeleton, and its semantics for text, JSON and crypto
What the rest of crafter-review stands on.
- project.cpp: a static crafter.review-lib and the crafter-review
executable; Crafter.Network without QUIC, pinned, or with --local from
the checkout next to this one; Crafter.LintRules' lite rules, pinned;
the version from CRAFTER_REVIEW_VERSION, git describe or 0.0.0-dev.
- :Core and :Driver: the version, PromptVersion 1, --version.
- :Json: nlohmann's ordered_json, which keeps key order and unknown keys,
so the files every driver on a machine shares survive a rewrite; dumps
in the indented file layout, the spaced one-line form and the compact
sorted form the structured-output schema needs byte for byte.
- :Crypto: SHA-256/SHA-1/MD5, HMAC, PBKDF2 through libcrypto; base64 and
base32 written out, because what they refuse, and with which message,
is pinned.
- :Unicode, Unicode 16.0.0's tables: whitespace, line breaks, decimal
digits, printable characters, case mappings and case-insensitive folds.
- :Text: string functions on code points, number parsing, the shortest
float form and half-even rounding, printed values, shell patterns, URL
splitting and unquoting, POSIX paths, universal newlines and the
replacing UTF-8 decoder.
Tests: Crypto (published vectors), Text (293 reference vectors).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:29:18 +01:00
" interfaces/Crafter.Review-Core " ,
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
" 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 " ,
feat(sql): the database helper and the TOTP helper, as subcommands
`crafter-review sql` hands the SQL to the driver's broker named in
REVIEW_GATES_DB; the broker runs it as one transaction, rolled back, and
streams the lines back with the exit code last. The client speaks protocol
3.0 over Crafter.Network's TCP client: cleartext, MD5 and SCRAM-SHA-256,
one Parse per statement, the transaction status as the backstop. The
splitter, the refusals, the table layout and every message work on code
points; connect and socket errors read "[Errno 111] Connection refused"
or "timed out". `crafter-review totp` prints "123456 (valid 17s)".
No sleep after the last connect attempt; TOTP reads the clock once; a
broker token that is no string gets the NO DATABASE answer and the exit
mark.
The goldens add the splitter, the comment stripping, the fingerprint, the
refusals, the first words, the headline, the cell, table, error and notice
layouts, the run's refusals and limits and 40 TOTP codes (2774 checks
now). tests/PgWire runs the helper over a Postgres stand-in and compares
its output with the goldens, line for line, plus the broker's protocol.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 07:20:00 +01:00
" interfaces/Crafter.Review-Totp " ,
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
" interfaces/Crafter.Review-Stream " ,
" interfaces/Crafter.Review-Prompt " ,
" interfaces/Crafter.Review-Config " ,
feat(seats): memory, the Playwright MCP config, and the seats library
:Memory: MemAvailable and the reserve policy, the sampler of a pass's peak
tree PSS (one sweep, a pause of three sweeps at least, stopped with the
driver), and the calibration file every driver on the machine shares,
re-read and written under its lock.
:Mcp: the pinned @playwright/mcp 0.0.83 arguments and the --mcp-config of
one pass, compact and in a fixed key order.
:Seats: the dotenv loader (token lines only, TOKEN7 inert), the one-word
probe (run under the supervisor, a missing binary reported with its errno
text), the window maths, the ranking, the Fable merge, the editor-bundle
lookup of the claude binary, the redaction of anything token-shaped, and
the report. This libc++ has no tzdb, so a zone by name converts through
the C library with TZ set, reading the system's zoneinfo.
tests/Seats: 92 checks against reference vectors, numbered in order, all
green.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 07:32:14 +01:00
" interfaces/Crafter.Review-Memory " ,
" interfaces/Crafter.Review-Mcp " ,
" interfaces/Crafter.Review-Seats " ,
feat(seatpool): the seat pool and the board several drivers share
The seats of .env and the ledger, the probe, placement, settling a
finished pass, the child's credentials, the OpenRouter seats, and the
board every driver on the machine shares, in one shape and under one
lock. A driver is alive while its lifetime lock is held; with no lock file
natively its pid and start time decide, and in the sandbox it is taken for
alive.
:Http is the HTTP the driver needs, on FetchHTTP1: a status outside 2xx is
HttpError, every other failure carries a fixed text. :Platform gains
MakeDirs, with the last directory's own mode, and errno texts for its
writes and locks.
The tests cover the seat pool and several drivers at once, less the checks
that drive the pool's Scheduler, Admission and Stacks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 08:15:03 +01:00
" interfaces/Crafter.Review-SeatPool " ,
feat(opencode): the OpenCode harness, checked against its goldens
The tool source generated from the schema, the home with its view, the
shared and per-process environments, the permission rules, the commands,
the warm-up under the supervisor, the event stream and the
classification, its patterns as hand-written scanners. The goldens record
the answer for each, a warm-up against a fake opencode included.
A timed-out supervised command now gets SIGTERM, so the supervisor takes
its tree down (SIGKILL 10 s later); any other child gets SIGKILL. :Json
gains DumpCompact.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 08:32:51 +01:00
" interfaces/Crafter.Review-OpenCode " ,
feat(pool): the pool - stacks, admission, the runner and the scheduler
The allowlists and the instrument checks (mcp_connected, db_answered,
exercised), the stack keys, Stacks and Admission, the Runner that runs one
claude or opencode process per pass, and the Scheduler with its retries,
rate-window pauses, the prompt-prefix warm-up, the seats and the board.
One thread per pass; each worker runs on its own copy of the job.
Every pass runs under the supervisor, so a timeout or an abort takes its
whole tree down; a timed-out pass reports exit -9, a SIGKILLed child's
code. The helpers the lenses run are this binary's `sql` and `totp`.
:Process gains an Append stream for the OpenCode meta line.
The tests cover the pool and its share of the commits-mode, seat-pool and
several-drivers checks, a fake claude under the supervisor included.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 08:55:00 +01:00
" interfaces/Crafter.Review-Pool " ,
feat(freeze): `crafter-review freeze`, and --verify that names a git upgrade
Freeze: identity, AI trailers by the consumer's rule (the pattern with
case-insensitive folds and its \s* that crosses lines), a clean tree, no
merges, a fast-forward, then format-patch, the hash, the dispositions
register and the optional detached worktree; --verify at push time. The
command line takes --opt=value, unique prefixes and the last of a repeat,
with a usage error at exit 3 like every command that cannot start; the
config is loaded and its warnings and problems reported first. The run
line it prints names this binary.
freeze.json records gitVersion. format-patch ends every patch with the
git version, so a fresh export under another git hashes differently;
--verify's MISMATCH says which git exported the artifact and which the
fresh copy, reading the patches' own signature when freeze.json does not
record it. freeze becomes a subreaper and takes down whatever gpg left
running for %G?.
tests/Freeze: 18 checks, plus the gitVersion record and both MISMATCH
messages.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 07:03:48 +01:00
" interfaces/Crafter.Review-Freeze " ,
feat: the crafter-review skeleton, and its semantics for text, JSON and crypto
What the rest of crafter-review stands on.
- project.cpp: a static crafter.review-lib and the crafter-review
executable; Crafter.Network without QUIC, pinned, or with --local from
the checkout next to this one; Crafter.LintRules' lite rules, pinned;
the version from CRAFTER_REVIEW_VERSION, git describe or 0.0.0-dev.
- :Core and :Driver: the version, PromptVersion 1, --version.
- :Json: nlohmann's ordered_json, which keeps key order and unknown keys,
so the files every driver on a machine shares survive a rewrite; dumps
in the indented file layout, the spaced one-line form and the compact
sorted form the structured-output schema needs byte for byte.
- :Crypto: SHA-256/SHA-1/MD5, HMAC, PBKDF2 through libcrypto; base64 and
base32 written out, because what they refuse, and with which message,
is pinned.
- :Unicode, Unicode 16.0.0's tables: whitespace, line breaks, decimal
digits, printable characters, case mappings and case-insensitive folds.
- :Text: string functions on code points, number parsing, the shortest
float form and half-even rounding, printed values, shell patterns, URL
splitting and unquoting, POSIX paths, universal newlines and the
replacing UTF-8 decoder.
Tests: Crypto (published vectors), Text (293 reference vectors).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:29:18 +01:00
" interfaces/Crafter.Review-Driver " ,
} ;
feat(pool): the pool - stacks, admission, the runner and the scheduler
The allowlists and the instrument checks (mcp_connected, db_answered,
exercised), the stack keys, Stacks and Admission, the Runner that runs one
claude or opencode process per pass, and the Scheduler with its retries,
rate-window pauses, the prompt-prefix warm-up, the seats and the board.
One thread per pass; each worker runs on its own copy of the job.
Every pass runs under the supervisor, so a timeout or an abort takes its
whole tree down; a timed-out pass reports exit -9, a SIGKILLed child's
code. The helpers the lenses run are this binary's `sql` and `totp`.
:Process gains an Append stream for the OpenCode meta line.
The tests cover the pool and its share of the commits-mode, seat-pool and
several-drivers checks, a fake claude under the supervisor included.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 08:55:00 +01:00
constexpr std : : array < std : : string_view , 27 > Implementations = {
feat: the crafter-review skeleton, and its semantics for text, JSON and crypto
What the rest of crafter-review stands on.
- project.cpp: a static crafter.review-lib and the crafter-review
executable; Crafter.Network without QUIC, pinned, or with --local from
the checkout next to this one; Crafter.LintRules' lite rules, pinned;
the version from CRAFTER_REVIEW_VERSION, git describe or 0.0.0-dev.
- :Core and :Driver: the version, PromptVersion 1, --version.
- :Json: nlohmann's ordered_json, which keeps key order and unknown keys,
so the files every driver on a machine shares survive a rewrite; dumps
in the indented file layout, the spaced one-line form and the compact
sorted form the structured-output schema needs byte for byte.
- :Crypto: SHA-256/SHA-1/MD5, HMAC, PBKDF2 through libcrypto; base64 and
base32 written out, because what they refuse, and with which message,
is pinned.
- :Unicode, Unicode 16.0.0's tables: whitespace, line breaks, decimal
digits, printable characters, case mappings and case-insensitive folds.
- :Text: string functions on code points, number parsing, the shortest
float form and half-even rounding, printed values, shell patterns, URL
splitting and unquoting, POSIX paths, universal newlines and the
replacing UTF-8 decoder.
Tests: Crypto (published vectors), Text (293 reference vectors).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:29:18 +01:00
" implementations/Crafter.Review-Text " ,
" implementations/Crafter.Review-Crypto " ,
feat(platform): processes that never outlive their pass, shared files, the board identity
:Process makes sure no child outlives what it was started for. SIGKILL to
the direct child alone would leave the Playwright server and Chromium
running after a timeout, and every pass running after a SIGKILLed driver:
- every child is forked by one long-lived spawner thread, the reaper's
registry locked across fork, so PR_SET_PDEATHSIG holds and a fast exit
is never reaped unregistered; one reaper thread owns waitpid(-1);
- the child gets an empty signal mask, SIGPIPE and SIGXFSZ at their
defaults, and nothing but its three streams (close_range); the driver
ignores SIGPIPE and takes SIGINT/SIGTERM/SIGHUP on a thread of its own;
- `crafter-review __supervise <argv>` is a pass's subreaper. It kills the
pass's whole tree, Chromium's detached process group included, when the
target exits, on SIGTERM, and when the driver dies, by its death signal.
- Run() captures both outputs without the deadlock.
The shared state the detached threads wait on is never destroyed: a
condition variable destroyed under a waiter makes glibc's
pthread_cond_destroy, and with it exit(), wait forever.
:Platform: the Flatpak sandbox decided once, the host's XDG directories
restored there; WriteAtomic and LockedUpdate, the read-modify-write of
the board, ledger, memory.json and unit-state.json every driver on the
machine shares, under flock(2) on the same side files; /proc readers; and
the identity other drivers can check: natively pid and start time, in the
sandbox the instance's host pid from bwrapinfo.json with /proc/1's start
time. The lifetime lock is created under a temporary name and renamed into
place, so no prober ever finds it unlocked while its driver lives.
Tests: Process (the three ways a pass's tree must die, return codes, a
missing program, capture, timeouts, fds, the child's signal state),
Platform (atomic writes, LockedUpdate against a damaged file, two writers,
and another process holding flock on the side file; /proc on a fake
tree; both identities; the lifetime lock; the XDG restore).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:49:46 +01:00
" implementations/Crafter.Review-Platform " ,
" implementations/Crafter.Review-Process " ,
feat(seatpool): the seat pool and the board several drivers share
The seats of .env and the ledger, the probe, placement, settling a
finished pass, the child's credentials, the OpenRouter seats, and the
board every driver on the machine shares, in one shape and under one
lock. A driver is alive while its lifetime lock is held; with no lock file
natively its pid and start time decide, and in the sandbox it is taken for
alive.
:Http is the HTTP the driver needs, on FetchHTTP1: a status outside 2xx is
HttpError, every other failure carries a fixed text. :Platform gains
MakeDirs, with the last directory's own mode, and errno texts for its
writes and locks.
The tests cover the seat pool and several drivers at once, less the checks
that drive the pool's Scheduler, Admission and Stacks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 08:15:03 +01:00
" implementations/Crafter.Review-Http " ,
feat: the crafter-review skeleton, and its semantics for text, JSON and crypto
What the rest of crafter-review stands on.
- project.cpp: a static crafter.review-lib and the crafter-review
executable; Crafter.Network without QUIC, pinned, or with --local from
the checkout next to this one; Crafter.LintRules' lite rules, pinned;
the version from CRAFTER_REVIEW_VERSION, git describe or 0.0.0-dev.
- :Core and :Driver: the version, PromptVersion 1, --version.
- :Json: nlohmann's ordered_json, which keeps key order and unknown keys,
so the files every driver on a machine shares survive a rewrite; dumps
in the indented file layout, the spaced one-line form and the compact
sorted form the structured-output schema needs byte for byte.
- :Crypto: SHA-256/SHA-1/MD5, HMAC, PBKDF2 through libcrypto; base64 and
base32 written out, because what they refuse, and with which message,
is pinned.
- :Unicode, Unicode 16.0.0's tables: whitespace, line breaks, decimal
digits, printable characters, case mappings and case-insensitive folds.
- :Text: string functions on code points, number parsing, the shortest
float form and half-even rounding, printed values, shell patterns, URL
splitting and unquoting, POSIX paths, universal newlines and the
replacing UTF-8 decoder.
Tests: Crypto (published vectors), Text (293 reference vectors).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:29:18 +01:00
" implementations/Crafter.Review-Core " ,
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
" 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 " ,
feat(sql): the database helper and the TOTP helper, as subcommands
`crafter-review sql` hands the SQL to the driver's broker named in
REVIEW_GATES_DB; the broker runs it as one transaction, rolled back, and
streams the lines back with the exit code last. The client speaks protocol
3.0 over Crafter.Network's TCP client: cleartext, MD5 and SCRAM-SHA-256,
one Parse per statement, the transaction status as the backstop. The
splitter, the refusals, the table layout and every message work on code
points; connect and socket errors read "[Errno 111] Connection refused"
or "timed out". `crafter-review totp` prints "123456 (valid 17s)".
No sleep after the last connect attempt; TOTP reads the clock once; a
broker token that is no string gets the NO DATABASE answer and the exit
mark.
The goldens add the splitter, the comment stripping, the fingerprint, the
refusals, the first words, the headline, the cell, table, error and notice
layouts, the run's refusals and limits and 40 TOTP codes (2774 checks
now). tests/PgWire runs the helper over a Postgres stand-in and compares
its output with the goldens, line for line, plus the broker's protocol.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 07:20:00 +01:00
" implementations/Crafter.Review-Totp " ,
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
" implementations/Crafter.Review-Stream " ,
" implementations/Crafter.Review-Prompt " ,
" implementations/Crafter.Review-Config " ,
feat(seats): memory, the Playwright MCP config, and the seats library
:Memory: MemAvailable and the reserve policy, the sampler of a pass's peak
tree PSS (one sweep, a pause of three sweeps at least, stopped with the
driver), and the calibration file every driver on the machine shares,
re-read and written under its lock.
:Mcp: the pinned @playwright/mcp 0.0.83 arguments and the --mcp-config of
one pass, compact and in a fixed key order.
:Seats: the dotenv loader (token lines only, TOKEN7 inert), the one-word
probe (run under the supervisor, a missing binary reported with its errno
text), the window maths, the ranking, the Fable merge, the editor-bundle
lookup of the claude binary, the redaction of anything token-shaped, and
the report. This libc++ has no tzdb, so a zone by name converts through
the C library with TZ set, reading the system's zoneinfo.
tests/Seats: 92 checks against reference vectors, numbered in order, all
green.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 07:32:14 +01:00
" implementations/Crafter.Review-Memory " ,
" implementations/Crafter.Review-Mcp " ,
" implementations/Crafter.Review-Seats " ,
feat(seatpool): the seat pool and the board several drivers share
The seats of .env and the ledger, the probe, placement, settling a
finished pass, the child's credentials, the OpenRouter seats, and the
board every driver on the machine shares, in one shape and under one
lock. A driver is alive while its lifetime lock is held; with no lock file
natively its pid and start time decide, and in the sandbox it is taken for
alive.
:Http is the HTTP the driver needs, on FetchHTTP1: a status outside 2xx is
HttpError, every other failure carries a fixed text. :Platform gains
MakeDirs, with the last directory's own mode, and errno texts for its
writes and locks.
The tests cover the seat pool and several drivers at once, less the checks
that drive the pool's Scheduler, Admission and Stacks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 08:15:03 +01:00
" implementations/Crafter.Review-SeatPool " ,
feat(opencode): the OpenCode harness, checked against its goldens
The tool source generated from the schema, the home with its view, the
shared and per-process environments, the permission rules, the commands,
the warm-up under the supervisor, the event stream and the
classification, its patterns as hand-written scanners. The goldens record
the answer for each, a warm-up against a fake opencode included.
A timed-out supervised command now gets SIGTERM, so the supervisor takes
its tree down (SIGKILL 10 s later); any other child gets SIGKILL. :Json
gains DumpCompact.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 08:32:51 +01:00
" implementations/Crafter.Review-OpenCode " ,
feat(pool): the pool - stacks, admission, the runner and the scheduler
The allowlists and the instrument checks (mcp_connected, db_answered,
exercised), the stack keys, Stacks and Admission, the Runner that runs one
claude or opencode process per pass, and the Scheduler with its retries,
rate-window pauses, the prompt-prefix warm-up, the seats and the board.
One thread per pass; each worker runs on its own copy of the job.
Every pass runs under the supervisor, so a timeout or an abort takes its
whole tree down; a timed-out pass reports exit -9, a SIGKILLed child's
code. The helpers the lenses run are this binary's `sql` and `totp`.
:Process gains an Append stream for the OpenCode meta line.
The tests cover the pool and its share of the commits-mode, seat-pool and
several-drivers checks, a fake claude under the supervisor included.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 08:55:00 +01:00
" implementations/Crafter.Review-Pool " ,
feat(freeze): `crafter-review freeze`, and --verify that names a git upgrade
Freeze: identity, AI trailers by the consumer's rule (the pattern with
case-insensitive folds and its \s* that crosses lines), a clean tree, no
merges, a fast-forward, then format-patch, the hash, the dispositions
register and the optional detached worktree; --verify at push time. The
command line takes --opt=value, unique prefixes and the last of a repeat,
with a usage error at exit 3 like every command that cannot start; the
config is loaded and its warnings and problems reported first. The run
line it prints names this binary.
freeze.json records gitVersion. format-patch ends every patch with the
git version, so a fresh export under another git hashes differently;
--verify's MISMATCH says which git exported the artifact and which the
fresh copy, reading the patches' own signature when freeze.json does not
record it. freeze becomes a subreaper and takes down whatever gpg left
running for %G?.
tests/Freeze: 18 checks, plus the gitVersion record and both MISMATCH
messages.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 07:03:48 +01:00
" implementations/Crafter.Review-Freeze " ,
feat: the crafter-review skeleton, and its semantics for text, JSON and crypto
What the rest of crafter-review stands on.
- project.cpp: a static crafter.review-lib and the crafter-review
executable; Crafter.Network without QUIC, pinned, or with --local from
the checkout next to this one; Crafter.LintRules' lite rules, pinned;
the version from CRAFTER_REVIEW_VERSION, git describe or 0.0.0-dev.
- :Core and :Driver: the version, PromptVersion 1, --version.
- :Json: nlohmann's ordered_json, which keeps key order and unknown keys,
so the files every driver on a machine shares survive a rewrite; dumps
in the indented file layout, the spaced one-line form and the compact
sorted form the structured-output schema needs byte for byte.
- :Crypto: SHA-256/SHA-1/MD5, HMAC, PBKDF2 through libcrypto; base64 and
base32 written out, because what they refuse, and with which message,
is pinned.
- :Unicode, Unicode 16.0.0's tables: whitespace, line breaks, decimal
digits, printable characters, case mappings and case-insensitive folds.
- :Text: string functions on code points, number parsing, the shortest
float form and half-even rounding, printed values, shell patterns, URL
splitting and unquoting, POSIX paths, universal newlines and the
replacing UTF-8 decoder.
Tests: Crypto (published vectors), Text (293 reference vectors).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:29:18 +01:00
" implementations/Crafter.Review-Driver " ,
} ;
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
// 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 " ;
feat: the crafter-review skeleton, and its semantics for text, JSON and crypto
What the rest of crafter-review stands on.
- project.cpp: a static crafter.review-lib and the crafter-review
executable; Crafter.Network without QUIC, pinned, or with --local from
the checkout next to this one; Crafter.LintRules' lite rules, pinned;
the version from CRAFTER_REVIEW_VERSION, git describe or 0.0.0-dev.
- :Core and :Driver: the version, PromptVersion 1, --version.
- :Json: nlohmann's ordered_json, which keeps key order and unknown keys,
so the files every driver on a machine shares survive a rewrite; dumps
in the indented file layout, the spaced one-line form and the compact
sorted form the structured-output schema needs byte for byte.
- :Crypto: SHA-256/SHA-1/MD5, HMAC, PBKDF2 through libcrypto; base64 and
base32 written out, because what they refuse, and with which message,
is pinned.
- :Unicode, Unicode 16.0.0's tables: whitespace, line breaks, decimal
digits, printable characters, case mappings and case-insensitive folds.
- :Text: string functions on code points, number parsing, the shortest
float form and half-even rounding, printed values, shell patterns, URL
splitting and unquoting, POSIX paths, universal newlines and the
replacing UTF-8 decoder.
Tests: Crypto (published vectors), Text (293 reference vectors).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:29:18 +01:00
// One per directory under tests/, each an ordinary main() that links the
// library: exit 0 passes, nonzero fails, 77 skips.
feat(pool): the pool - stacks, admission, the runner and the scheduler
The allowlists and the instrument checks (mcp_connected, db_answered,
exercised), the stack keys, Stacks and Admission, the Runner that runs one
claude or opencode process per pass, and the Scheduler with its retries,
rate-window pauses, the prompt-prefix warm-up, the seats and the board.
One thread per pass; each worker runs on its own copy of the job.
Every pass runs under the supervisor, so a timeout or an abort takes its
whole tree down; a timed-out pass reports exit -9, a SIGKILLed child's
code. The helpers the lenses run are this binary's `sql` and `totp`.
:Process gains an Append stream for the OpenCode meta line.
The tests cover the pool and its share of the commits-mode, seat-pool and
several-drivers checks, a fake claude under the supervisor included.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 08:55:00 +01:00
constexpr std : : array < std : : string_view , 20 > Tests = {
feat: the crafter-review skeleton, and its semantics for text, JSON and crypto
What the rest of crafter-review stands on.
- project.cpp: a static crafter.review-lib and the crafter-review
executable; Crafter.Network without QUIC, pinned, or with --local from
the checkout next to this one; Crafter.LintRules' lite rules, pinned;
the version from CRAFTER_REVIEW_VERSION, git describe or 0.0.0-dev.
- :Core and :Driver: the version, PromptVersion 1, --version.
- :Json: nlohmann's ordered_json, which keeps key order and unknown keys,
so the files every driver on a machine shares survive a rewrite; dumps
in the indented file layout, the spaced one-line form and the compact
sorted form the structured-output schema needs byte for byte.
- :Crypto: SHA-256/SHA-1/MD5, HMAC, PBKDF2 through libcrypto; base64 and
base32 written out, because what they refuse, and with which message,
is pinned.
- :Unicode, Unicode 16.0.0's tables: whitespace, line breaks, decimal
digits, printable characters, case mappings and case-insensitive folds.
- :Text: string functions on code points, number parsing, the shortest
float form and half-even rounding, printed values, shell patterns, URL
splitting and unquoting, POSIX paths, universal newlines and the
replacing UTF-8 decoder.
Tests: Crypto (published vectors), Text (293 reference vectors).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:29:18 +01:00
" Crypto " ,
" Text " ,
feat(platform): processes that never outlive their pass, shared files, the board identity
:Process makes sure no child outlives what it was started for. SIGKILL to
the direct child alone would leave the Playwright server and Chromium
running after a timeout, and every pass running after a SIGKILLed driver:
- every child is forked by one long-lived spawner thread, the reaper's
registry locked across fork, so PR_SET_PDEATHSIG holds and a fast exit
is never reaped unregistered; one reaper thread owns waitpid(-1);
- the child gets an empty signal mask, SIGPIPE and SIGXFSZ at their
defaults, and nothing but its three streams (close_range); the driver
ignores SIGPIPE and takes SIGINT/SIGTERM/SIGHUP on a thread of its own;
- `crafter-review __supervise <argv>` is a pass's subreaper. It kills the
pass's whole tree, Chromium's detached process group included, when the
target exits, on SIGTERM, and when the driver dies, by its death signal.
- Run() captures both outputs without the deadlock.
The shared state the detached threads wait on is never destroyed: a
condition variable destroyed under a waiter makes glibc's
pthread_cond_destroy, and with it exit(), wait forever.
:Platform: the Flatpak sandbox decided once, the host's XDG directories
restored there; WriteAtomic and LockedUpdate, the read-modify-write of
the board, ledger, memory.json and unit-state.json every driver on the
machine shares, under flock(2) on the same side files; /proc readers; and
the identity other drivers can check: natively pid and start time, in the
sandbox the instance's host pid from bwrapinfo.json with /proc/1's start
time. The lifetime lock is created under a temporary name and renamed into
place, so no prober ever finds it unlocked while its driver lives.
Tests: Process (the three ways a pass's tree must die, return codes, a
missing program, capture, timeouts, fds, the child's signal state),
Platform (atomic writes, LockedUpdate against a damaged file, two writers,
and another process holding flock on the side file; /proc on a fake
tree; both identities; the lifetime lock; the XDG restore).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:49:46 +01:00
" Platform " ,
" Process " ,
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
" Goldens " ,
test(pipeline): the checks of the pure pipeline
Stream, Normalize, Merge, Dispositions, Config, CodeKeys and the pure half
of CommitsMode, each a test of its own (131 checks). The fixture rewrites
are checked in (code-keys/<name>/, commits3/), so the suite reads fixtures
and edits nothing. The allowlist, command-line and MCP checks of
CommitsMode come with the pool they test.
Among them: this binary's `<exe> sql` spelling counts as a SQL call, and a
result line with a raw U+2028 in a JSON string is still the result line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:56:09 +01:00
" Stream " ,
" Normalize " ,
" Merge " ,
" Dispositions " ,
" Config " ,
" CommitsMode " ,
" CodeKeys " ,
feat(freeze): `crafter-review freeze`, and --verify that names a git upgrade
Freeze: identity, AI trailers by the consumer's rule (the pattern with
case-insensitive folds and its \s* that crosses lines), a clean tree, no
merges, a fast-forward, then format-patch, the hash, the dispositions
register and the optional detached worktree; --verify at push time. The
command line takes --opt=value, unique prefixes and the last of a repeat,
with a usage error at exit 3 like every command that cannot start; the
config is loaded and its warnings and problems reported first. The run
line it prints names this binary.
freeze.json records gitVersion. format-patch ends every patch with the
git version, so a fresh export under another git hashes differently;
--verify's MISMATCH says which git exported the artifact and which the
fresh copy, reading the patches' own signature when freeze.json does not
record it. freeze becomes a subreaper and takes down whatever gpg left
running for %G?.
tests/Freeze: 18 checks, plus the gitVersion record and both MISMATCH
messages.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 07:03:48 +01:00
" Freeze " ,
feat(sql): the database helper and the TOTP helper, as subcommands
`crafter-review sql` hands the SQL to the driver's broker named in
REVIEW_GATES_DB; the broker runs it as one transaction, rolled back, and
streams the lines back with the exit code last. The client speaks protocol
3.0 over Crafter.Network's TCP client: cleartext, MD5 and SCRAM-SHA-256,
one Parse per statement, the transaction status as the backstop. The
splitter, the refusals, the table layout and every message work on code
points; connect and socket errors read "[Errno 111] Connection refused"
or "timed out". `crafter-review totp` prints "123456 (valid 17s)".
No sleep after the last connect attempt; TOTP reads the clock once; a
broker token that is no string gets the NO DATABASE answer and the exit
mark.
The goldens add the splitter, the comment stripping, the fingerprint, the
refusals, the first words, the headline, the cell, table, error and notice
layouts, the run's refusals and limits and 40 TOTP codes (2774 checks
now). tests/PgWire runs the helper over a Postgres stand-in and compares
its output with the goldens, line for line, plus the broker's protocol.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 07:20:00 +01:00
" PgWire " ,
feat(seats): memory, the Playwright MCP config, and the seats library
:Memory: MemAvailable and the reserve policy, the sampler of a pass's peak
tree PSS (one sweep, a pause of three sweeps at least, stopped with the
driver), and the calibration file every driver on the machine shares,
re-read and written under its lock.
:Mcp: the pinned @playwright/mcp 0.0.83 arguments and the --mcp-config of
one pass, compact and in a fixed key order.
:Seats: the dotenv loader (token lines only, TOKEN7 inert), the one-word
probe (run under the supervisor, a missing binary reported with its errno
text), the window maths, the ranking, the Fable merge, the editor-bundle
lookup of the claude binary, the redaction of anything token-shaped, and
the report. This libc++ has no tzdb, so a zone by name converts through
the C library with TZ set, reading the system's zoneinfo.
tests/Seats: 92 checks against reference vectors, numbered in order, all
green.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 07:32:14 +01:00
" Seats " ,
feat(seatpool): the seat pool and the board several drivers share
The seats of .env and the ledger, the probe, placement, settling a
finished pass, the child's credentials, the OpenRouter seats, and the
board every driver on the machine shares, in one shape and under one
lock. A driver is alive while its lifetime lock is held; with no lock file
natively its pid and start time decide, and in the sandbox it is taken for
alive.
:Http is the HTTP the driver needs, on FetchHTTP1: a status outside 2xx is
HttpError, every other failure carries a fixed text. :Platform gains
MakeDirs, with the last directory's own mode, and errno texts for its
writes and locks.
The tests cover the seat pool and several drivers at once, less the checks
that drive the pool's Scheduler, Admission and Stacks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 08:15:03 +01:00
" SeatPool " ,
" Drivers " ,
feat(opencode): the OpenCode harness, checked against its goldens
The tool source generated from the schema, the home with its view, the
shared and per-process environments, the permission rules, the commands,
the warm-up under the supervisor, the event stream and the
classification, its patterns as hand-written scanners. The goldens record
the answer for each, a warm-up against a fake opencode included.
A timed-out supervised command now gets SIGTERM, so the supervisor takes
its tree down (SIGKILL 10 s later); any other child gets SIGKILL. :Json
gains DumpCompact.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 08:32:51 +01:00
" OpenCode " ,
feat(pool): the pool - stacks, admission, the runner and the scheduler
The allowlists and the instrument checks (mcp_connected, db_answered,
exercised), the stack keys, Stacks and Admission, the Runner that runs one
claude or opencode process per pass, and the Scheduler with its retries,
rate-window pauses, the prompt-prefix warm-up, the seats and the board.
One thread per pass; each worker runs on its own copy of the job.
Every pass runs under the supervisor, so a timeout or an abort takes its
whole tree down; a timed-out pass reports exit -9, a SIGKILLed child's
code. The helpers the lenses run are this binary's `sql` and `totp`.
:Process gains an Append stream for the OpenCode meta line.
The tests cover the pool and its share of the commits-mode, seat-pool and
several-drivers checks, a fake claude under the supervisor included.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 08:55:00 +01:00
" Runner " ,
" Scheduler " ,
feat: the crafter-review skeleton, and its semantics for text, JSON and crypto
What the rest of crafter-review stands on.
- project.cpp: a static crafter.review-lib and the crafter-review
executable; Crafter.Network without QUIC, pinned, or with --local from
the checkout next to this one; Crafter.LintRules' lite rules, pinned;
the version from CRAFTER_REVIEW_VERSION, git describe or 0.0.0-dev.
- :Core and :Driver: the version, PromptVersion 1, --version.
- :Json: nlohmann's ordered_json, which keeps key order and unknown keys,
so the files every driver on a machine shares survive a rewrite; dumps
in the indented file layout, the spaced one-line form and the compact
sorted form the structured-output schema needs byte for byte.
- :Crypto: SHA-256/SHA-1/MD5, HMAC, PBKDF2 through libcrypto; base64 and
base32 written out, because what they refuse, and with which message,
is pinned.
- :Unicode, Unicode 16.0.0's tables: whitespace, line breaks, decimal
digits, printable characters, case mappings and case-insensitive folds.
- :Text: string functions on code points, number parsing, the shortest
float form and half-even rounding, printed values, shell patterns, URL
splitting and unquoting, POSIX paths, universal newlines and the
replacing UTF-8 decoder.
Tests: Crypto (published vectors), Text (293 reference vectors).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:29:18 +01:00
} ;
// The version the binary reports: CI sets it from the tag, a checkout
// describes itself, anything else is a development build. A define on
// the library, so each version is its own library variant.
std : : string Version ( ) {
if ( const char * env = std : : getenv ( " CRAFTER_REVIEW_VERSION " ) ; env & & * env ) return env ;
auto described = RunCommandWithTimeout ( " git describe --tags --always --dirty --exclude=latest 2>/dev/null " , std : : chrono : : seconds ( 10 ) ) ;
std : : string version = described . output ;
while ( ! version . empty ( ) & & ( version . back ( ) = = ' \n ' | | version . back ( ) = = ' \r ' ) ) version . pop_back ( ) ;
if ( described . exitCode ! = 0 | | version . empty ( ) ) return " 0.0.0-dev " ;
return version ;
}
build(flatpak): net.catcrafts.CrafterReview on the Crafter.Build base
The manifest builds on the Crafter.Build Flatpak (base:
net.catcrafts.CrafterBuild): its crafter-build, LLVM 23 and libc++
compile this project inside flatpak-builder, and crafter-build test runs
there too. Node 24.22.0 (for the Playwright MCP server) and a static
ripgrep 15.2.0 are bundled, pinned by sha256; claude is not, being
proprietary. finish-args: the network, the host's files and /tmp, and
gnupg's keyboxd socket only, never the agent.
The base's files belong to no module of this manifest, so `cleanup` does
not reach them: prune-base.sh keeps a named list (the binary, Node, rg,
the libc++ the binary links, share/crafter-review, this app's metainfo
and licences) and removes the rest, whatever a newer base adds.
`crafter-build run flatpak [--base=<branch>] [--jobs=N]` builds it and
smoke-tests --version and ldd through `flatpak build`; `run install`
installs it as the `local` branch. Until a Crafter.Build release with
scripts is on stable, `--base=local` builds against Crafter.Build's own
local install, from a gitignored manifest copy whose cache is its own.
Built that way: 4 tests green in the sandbox, the charter sha256s the
native build prints, no library missing, RUNPATH /app/lib only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:01:19 +01:00
// The local Flatpak: `crafter-build run flatpak` builds it from this
// checkout and `crafter-build run install` installs that build, as
// Crafter.Build's own scripts do. --base=<branch> builds on another branch
// of the Crafter.Build base app than stable: until a Crafter.Build release
// with scripts is on stable, `--base=local` (the branch Crafter.Build's own
// `run install` makes) is what builds this project.
struct FlatpakPaths {
fs : : path manifest ;
// flatpak-builder's downloads, ccache and per-module cache.
fs : : path state ;
// The OSTree repo the build is exported to; `install` reads it.
fs : : path repo ;
fs : : path buildDir ;
} ;
// Everything under <project>/build/flatpak, a fixed name rather than a
// BuildDir(): the Flatpak is compiled by the toolchain inside the sandbox,
// not by the host variant. flatpak-builder keys its cache on the
// manifest's absolute path, so a branch other than stable gets a manifest
// copy of its own next to the original (gitignored), and with it a cache
// of its own.
FlatpakPaths FlatpakLayout ( const fs : : path & projectDir , std : : string_view base ) {
const fs : : path root = projectDir / " build " / " flatpak " ;
const fs : : path packaging = projectDir / " packaging " / " flatpak " ;
return {
. manifest = base = = " stable " ? packaging / " net.catcrafts.CrafterReview.yaml " : packaging / std : : format ( " {}-base.yaml " , base ) ,
. state = root / " state " ,
. repo = root / " repo " ,
. buildDir = root / " build-dir " ,
} ;
}
// Both scripts drive the host's flatpak, which the sandbox of a Flatpak
// crafter-build does not have.
bool RefusedInSandbox ( std : : string_view script ) {
if ( ! fs : : exists ( " /.flatpak-info " ) ) return false ;
std : : println ( std : : cerr , " run {0}: needs the host's flatpak, which the Flatpak build of crafter-build cannot reach. Use a native crafter-build " , script ) ;
return true ;
}
// flatpak-builder as a host package, else the org.flatpak.Builder app.
// Empty when neither is installed.
std : : string FlatpakBuilder ( ) {
if ( RunCommandWithTimeout ( " flatpak-builder --version " , std : : chrono : : seconds ( 10 ) ) . exitCode = = 0 ) return " flatpak-builder " ;
if ( RunCommandWithTimeout ( " flatpak info org.flatpak.Builder " , std : : chrono : : seconds ( 10 ) ) . exitCode = = 0 ) return " flatpak run org.flatpak.Builder " ;
return " " ;
}
// A repo path as the file:// URL of a remote. Percent-encoded, because
// `remote-modify --url=` stores what it is given as it is.
std : : string FileUrl ( const fs : : path & path ) {
std : : string url = " file:// " ;
for ( const char c : path . string ( ) ) {
const bool plain = ( c > = ' a ' & & c < = ' z ' ) | | ( c > = ' A ' & & c < = ' Z ' ) | | ( c > = ' 0 ' & & c < = ' 9 ' ) | | std : : string_view ( " /-._~ " ) . contains ( c ) ;
if ( plain ) {
url . push_back ( c ) ;
} else {
url + = std : : format ( " %{:02X} " , static_cast < std : : uint8_t > ( c ) ) ;
}
}
return url ;
}
std : : int32_t BuildFlatpak ( ScriptContext & ctx ) {
if ( RefusedInSandbox ( " flatpak " ) ) return 1 ;
std : : string jobs ;
std : : string base = " stable " ;
for ( const std : : string & arg : ctx . args ) {
if ( arg . starts_with ( " --base= " ) & & arg . size ( ) > 7 ) {
base = arg . substr ( 7 ) ;
continue ;
}
const std : : string_view count = arg . starts_with ( " --jobs= " ) ? std : : string_view ( arg ) . substr ( 7 ) : std : : string_view ( ) ;
if ( count . empty ( ) | | ! std : : ranges : : all_of ( count , [ ] ( char c ) { return c > = ' 0 ' & & c < = ' 9 ' ; } ) ) {
std : : println ( std : : cerr , " run flatpak: unknown argument '{}' (only --jobs=<N> and --base=<branch> are accepted) " , arg ) ;
return 1 ;
}
jobs = std : : format ( " --jobs={} " , count ) ;
}
if ( ! std : : ranges : : all_of ( base , [ ] ( char c ) { return std : : isalnum ( static_cast < std : : uint8_t > ( c ) ) | | c = = ' - ' | | c = = ' _ ' | | c = = ' . ' ; } ) ) {
std : : println ( std : : cerr , " run flatpak: '{}' is not a branch name " , base ) ;
return 1 ;
}
if ( RunCommandWithTimeout ( std : : format ( " flatpak info net.catcrafts.CrafterBuild//{} " , base ) , std : : chrono : : seconds ( 10 ) ) . exitCode ! = 0 ) {
std : : println ( std : : cerr , " run flatpak: the base app is not installed: flatpak install catcrafts net.catcrafts.CrafterBuild//{} " , base ) ;
return 1 ;
}
const std : : string builder = FlatpakBuilder ( ) ;
if ( builder . empty ( ) ) {
std : : println ( std : : cerr , " run flatpak: neither flatpak-builder nor the org.flatpak.Builder app is installed (flatpak install flathub org.flatpak.Builder) " ) ;
return 1 ;
}
const FlatpakPaths paths = FlatpakLayout ( ctx . projectDir , base ) ;
if ( base ! = " stable " ) {
// The manifest with only base-version changed.
std : : ifstream in ( FlatpakLayout ( ctx . projectDir , " stable " ) . manifest ) ;
const std : : string manifest ( ( std : : istreambuf_iterator < char > ( in ) ) , std : : istreambuf_iterator < char > ( ) ) ;
constexpr std : : string_view Line = " base-version: stable \n " ;
const std : : size_t at = manifest . find ( Line ) ;
if ( at = = std : : string : : npos ) {
std : : println ( std : : cerr , " run flatpak: the manifest has no `{}` line to replace " , Line . substr ( 0 , Line . size ( ) - 1 ) ) ;
return 1 ;
}
std : : ofstream ( paths . manifest ) < < manifest . substr ( 0 , at ) < < std : : format ( " base-version: {} \n " , base ) < < manifest . substr ( at + Line . size ( ) ) ;
}
const std : : string buildDir = ShellQuote ( paths . buildDir . string ( ) ) ;
if ( const std : : int32_t code = ctx . Run ( std : : format ( " {}{} --user --force-clean --ccache --state-dir={} --repo={} --default-branch=local {} {} " , builder , jobs , ShellQuote ( paths . state . string ( ) ) , ShellQuote ( paths . repo . string ( ) ) , buildDir , ShellQuote ( paths . manifest . string ( ) ) ) ) ; code ! = 0 ) return code ;
// The smoke test, through `flatpak build` and not `<builder> --run`:
// the org.flatpak.Builder app reports --run's exit status inverted.
if ( const std : : int32_t code = ctx . Run ( std : : format ( " flatpak build {} crafter-review --version " , buildDir ) ) ; code ! = 0 ) return code ;
return ctx . Run ( std : : format ( " flatpak build {} sh -c 'ldd /app/bin/crafter-review | grep \" not found \" && exit 1 || exit 0' " , buildDir ) ) ;
}
std : : int32_t InstallFlatpak ( ScriptContext & ctx ) {
if ( RefusedInSandbox ( " install " ) ) return 1 ;
if ( ! ctx . args . empty ( ) ) {
std : : println ( std : : cerr , " run install: takes no arguments (got '{}') " , ctx . args . front ( ) ) ;
return 1 ;
}
const FlatpakPaths paths = FlatpakLayout ( ctx . projectDir , " stable " ) ;
if ( ! fs : : exists ( paths . repo / " config " ) ) {
std : : println ( std : : cerr , " run install: nothing built yet, run: crafter-build run flatpak " ) ;
return 1 ;
}
const std : : string url = ShellQuote ( FileUrl ( paths . repo ) ) ;
if ( const std : : int32_t code = ctx . Run ( std : : format ( " flatpak remote-add --user --if-not-exists --no-gpg-verify crafter-review-local {} " , url ) ) ; code ! = 0 ) return code ;
if ( const std : : int32_t code = ctx . Run ( std : : format ( " flatpak remote-modify --user --url={} crafter-review-local " , url ) ) ; code ! = 0 ) return code ;
if ( const std : : int32_t code = ctx . Run ( " flatpak install --user --noninteractive --or-update crafter-review-local net.catcrafts.CrafterReview//local " ) ; code ! = 0 ) return code ;
if ( const std : : int32_t code = ctx . Run ( " flatpak make-current --user net.catcrafts.CrafterReview local " ) ; code ! = 0 ) return code ;
std : : println (
R " (
` flatpak run net . catcrafts . CrafterReview ` now starts this build .
Back to a published branch , keeping this one installed :
flatpak make - current - - user net . catcrafts . CrafterReview < branch >
Remove it ( do this before deleting build / , which holds the repo the remote points at ) :
flatpak uninstall - - user net . catcrafts . CrafterReview //local
flatpak remote - delete - - user crafter - review - local ) " );
return 0 ;
}
feat: the crafter-review skeleton, and its semantics for text, JSON and crypto
What the rest of crafter-review stands on.
- project.cpp: a static crafter.review-lib and the crafter-review
executable; Crafter.Network without QUIC, pinned, or with --local from
the checkout next to this one; Crafter.LintRules' lite rules, pinned;
the version from CRAFTER_REVIEW_VERSION, git describe or 0.0.0-dev.
- :Core and :Driver: the version, PromptVersion 1, --version.
- :Json: nlohmann's ordered_json, which keeps key order and unknown keys,
so the files every driver on a machine shares survive a rewrite; dumps
in the indented file layout, the spaced one-line form and the compact
sorted form the structured-output schema needs byte for byte.
- :Crypto: SHA-256/SHA-1/MD5, HMAC, PBKDF2 through libcrypto; base64 and
base32 written out, because what they refuse, and with which message,
is pinned.
- :Unicode, Unicode 16.0.0's tables: whitespace, line breaks, decimal
digits, printable characters, case mappings and case-insensitive folds.
- :Text: string functions on code points, number parsing, the shortest
float form and half-even rounding, printed values, shell patterns, URL
splitting and unquoting, POSIX paths, universal newlines and the
replacing UTF-8 decoder.
Tests: Crypto (published vectors), Text (293 reference vectors).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:29:18 +01:00
}
extern " C " Configuration CrafterBuildProject ( std : : span < const std : : string_view > args ) {
// Crafter.Network for its TCP and HTTP/1.1 clients and listener, without
// QUIC: msquic is most of a fresh build and nothing here speaks HTTP/3.
// From forgejo at a pinned commit, or with --local from the checkout next
// to this one (which is also how Crafter.Network then finds
// Crafter.Thread).
std : : vector < std : : string > depArgs ( args . begin ( ) , args . end ( ) ) ;
depArgs . emplace_back ( " --no-quic " ) ;
const bool useLocal = std : : ranges : : find ( args , std : : string_view ( " --local " ) ) ! = args . end ( ) ;
Configuration * network = useLocal
? LocalProject ( { . projectFile = " ../Crafter.Network/project.cpp " , . args = depArgs } )
: GitProject ( {
. source = { . url = " https://forgejo.catcrafts.net/Catcrafts/Crafter.Network.git " , . commit = " f68321685006be65f6bc0436fd0175611f1e0a55 " } ,
. args = depArgs ,
} ) ;
static auto ReviewLib = std : : make_unique < Configuration > ( ) ;
ReviewLib - > path = " ./ " ;
ReviewLib - > name = " crafter.review-lib " ;
ReviewLib - > outputName = " crafter-review " ;
ApplyStandardArgs ( * ReviewLib , args ) ;
ReviewLib - > type = ConfigurationType : : LibraryStatic ;
ReviewLib - > dependencies = { network } ;
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
ReviewLib - > compileFlags . emplace_back ( NoContraction ) ;
feat: the crafter-review skeleton, and its semantics for text, JSON and crypto
What the rest of crafter-review stands on.
- project.cpp: a static crafter.review-lib and the crafter-review
executable; Crafter.Network without QUIC, pinned, or with --local from
the checkout next to this one; Crafter.LintRules' lite rules, pinned;
the version from CRAFTER_REVIEW_VERSION, git describe or 0.0.0-dev.
- :Core and :Driver: the version, PromptVersion 1, --version.
- :Json: nlohmann's ordered_json, which keeps key order and unknown keys,
so the files every driver on a machine shares survive a rewrite; dumps
in the indented file layout, the spaced one-line form and the compact
sorted form the structured-output schema needs byte for byte.
- :Crypto: SHA-256/SHA-1/MD5, HMAC, PBKDF2 through libcrypto; base64 and
base32 written out, because what they refuse, and with which message,
is pinned.
- :Unicode, Unicode 16.0.0's tables: whitespace, line breaks, decimal
digits, printable characters, case mappings and case-insensitive folds.
- :Text: string functions on code points, number parsing, the shortest
float form and half-even rounding, printed values, shell patterns, URL
splitting and unquoting, POSIX paths, universal newlines and the
replacing UTF-8 decoder.
Tests: Crypto (published vectors), Text (293 reference vectors).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:29:18 +01:00
// 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 ( ) ) } ) ;
{
std : : vector < fs : : path > interfaces ( Interfaces . begin ( ) , Interfaces . end ( ) ) ;
std : : vector < fs : : path > implementations ( Implementations . begin ( ) , Implementations . end ( ) ) ;
ReviewLib - > GetInterfacesAndImplementations ( interfaces , implementations ) ;
}
Configuration cfg ;
cfg . path = " ./ " ;
cfg . name = " crafter.review-exe " ;
cfg . outputName = " crafter-review " ;
ApplyStandardArgs ( cfg , args ) ;
cfg . type = ConfigurationType : : Executable ;
cfg . dependencies = { ReviewLib . get ( ) } ;
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
cfg . compileFlags . emplace_back ( NoContraction ) ;
feat: the crafter-review skeleton, and its semantics for text, JSON and crypto
What the rest of crafter-review stands on.
- project.cpp: a static crafter.review-lib and the crafter-review
executable; Crafter.Network without QUIC, pinned, or with --local from
the checkout next to this one; Crafter.LintRules' lite rules, pinned;
the version from CRAFTER_REVIEW_VERSION, git describe or 0.0.0-dev.
- :Core and :Driver: the version, PromptVersion 1, --version.
- :Json: nlohmann's ordered_json, which keeps key order and unknown keys,
so the files every driver on a machine shares survive a rewrite; dumps
in the indented file layout, the spaced one-line form and the compact
sorted form the structured-output schema needs byte for byte.
- :Crypto: SHA-256/SHA-1/MD5, HMAC, PBKDF2 through libcrypto; base64 and
base32 written out, because what they refuse, and with which message,
is pinned.
- :Unicode, Unicode 16.0.0's tables: whitespace, line breaks, decimal
digits, printable characters, case mappings and case-insensitive folds.
- :Text: string functions on code points, number parsing, the shortest
float form and half-even rounding, printed values, shell patterns, URL
splitting and unquoting, POSIX paths, universal newlines and the
replacing UTF-8 decoder.
Tests: Crypto (published vectors), Text (293 reference vectors).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:29:18 +01:00
{
std : : array < fs : : path , 0 > interfaces = { } ;
std : : array < fs : : path , 1 > implementations = { " implementations/main " } ;
cfg . GetInterfacesAndImplementations ( interfaces , implementations ) ;
}
for ( const std : : string_view test : Tests ) {
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
cfg . AddTest ( test ) . Dependencies ( { ReviewLib . get ( ) } ) . CompileFlag ( std : : string ( NoContraction ) ) ;
feat: the crafter-review skeleton, and its semantics for text, JSON and crypto
What the rest of crafter-review stands on.
- project.cpp: a static crafter.review-lib and the crafter-review
executable; Crafter.Network without QUIC, pinned, or with --local from
the checkout next to this one; Crafter.LintRules' lite rules, pinned;
the version from CRAFTER_REVIEW_VERSION, git describe or 0.0.0-dev.
- :Core and :Driver: the version, PromptVersion 1, --version.
- :Json: nlohmann's ordered_json, which keeps key order and unknown keys,
so the files every driver on a machine shares survive a rewrite; dumps
in the indented file layout, the spaced one-line form and the compact
sorted form the structured-output schema needs byte for byte.
- :Crypto: SHA-256/SHA-1/MD5, HMAC, PBKDF2 through libcrypto; base64 and
base32 written out, because what they refuse, and with which message,
is pinned.
- :Unicode, Unicode 16.0.0's tables: whitespace, line breaks, decimal
digits, printable characters, case mappings and case-insensitive folds.
- :Text: string functions on code points, number parsing, the shortest
float form and half-even rounding, printed values, shell patterns, URL
splitting and unquoting, POSIX paths, universal newlines and the
replacing UTF-8 decoder.
Tests: Crypto (published vectors), Text (293 reference vectors).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:29:18 +01:00
}
LintRules : : AddLiteRules ( cfg ) ;
build(flatpak): net.catcrafts.CrafterReview on the Crafter.Build base
The manifest builds on the Crafter.Build Flatpak (base:
net.catcrafts.CrafterBuild): its crafter-build, LLVM 23 and libc++
compile this project inside flatpak-builder, and crafter-build test runs
there too. Node 24.22.0 (for the Playwright MCP server) and a static
ripgrep 15.2.0 are bundled, pinned by sha256; claude is not, being
proprietary. finish-args: the network, the host's files and /tmp, and
gnupg's keyboxd socket only, never the agent.
The base's files belong to no module of this manifest, so `cleanup` does
not reach them: prune-base.sh keeps a named list (the binary, Node, rg,
the libc++ the binary links, share/crafter-review, this app's metainfo
and licences) and removes the rest, whatever a newer base adds.
`crafter-build run flatpak [--base=<branch>] [--jobs=N]` builds it and
smoke-tests --version and ldd through `flatpak build`; `run install`
installs it as the `local` branch. Until a Crafter.Build release with
scripts is on stable, `--base=local` builds against Crafter.Build's own
local install, from a gitignored manifest copy whose cache is its own.
Built that way: 4 tests green in the sandbox, the charter sha256s the
native build prints, no library missing, RUNPATH /app/lib only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:01:19 +01:00
cfg . scripts . push_back ( { " flatpak " , BuildFlatpak } ) ;
cfg . scripts . push_back ( { " install " , InstallFlatpak } ) ;
feat: the crafter-review skeleton, and its semantics for text, JSON and crypto
What the rest of crafter-review stands on.
- project.cpp: a static crafter.review-lib and the crafter-review
executable; Crafter.Network without QUIC, pinned, or with --local from
the checkout next to this one; Crafter.LintRules' lite rules, pinned;
the version from CRAFTER_REVIEW_VERSION, git describe or 0.0.0-dev.
- :Core and :Driver: the version, PromptVersion 1, --version.
- :Json: nlohmann's ordered_json, which keeps key order and unknown keys,
so the files every driver on a machine shares survive a rewrite; dumps
in the indented file layout, the spaced one-line form and the compact
sorted form the structured-output schema needs byte for byte.
- :Crypto: SHA-256/SHA-1/MD5, HMAC, PBKDF2 through libcrypto; base64 and
base32 written out, because what they refuse, and with which message,
is pinned.
- :Unicode, Unicode 16.0.0's tables: whitespace, line breaks, decimal
digits, printable characters, case mappings and case-insensitive folds.
- :Text: string functions on code points, number parsing, the shortest
float form and half-even rounding, printed values, shell patterns, URL
splitting and unquoting, POSIX paths, universal newlines and the
replacing UTF-8 decoder.
Tests: Crypto (published vectors), Text (293 reference vectors).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 05:29:18 +01:00
return cfg ;
}