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®
|
|
|
|
|
|
|
|
|
|
export module Crafter.Review:Prompt;
|
|
|
|
|
import std;
|
|
|
|
|
import :Json;
|
|
|
|
|
|
|
|
|
|
// The system text and the layered prompt: the run layer, shared by every
|
|
|
|
|
// process of the run, then the lens layer, shared per lens, then the tail,
|
|
|
|
|
// this pass. Byte-identical prefixes are what the shared prompt cache keys
|
|
|
|
|
// on, so every literal here is fixed to the byte (the goldens hold them).
|
|
|
|
|
export namespace Crafter::Review::Prompt {
|
|
|
|
|
constexpr std::string_view SepLens = "\n\n==================== LENS ====================\n\n";
|
|
|
|
|
constexpr std::string_view SepTail = "\n\n==================== SCOPE OF THIS PASS ====================\n\n";
|
|
|
|
|
constexpr std::string_view SepRun = "\n\n==================== THIS RUN ====================\n\n";
|
|
|
|
|
|
|
|
|
|
extern const std::string_view GenericVocab;
|
|
|
|
|
// WHOLE_TEXT['first-repo'] and WHOLE_TEXT['functional'].
|
|
|
|
|
extern const std::string_view WholeFirstRepo;
|
|
|
|
|
extern const std::string_view WholeFunctional;
|
|
|
|
|
extern const std::string_view FunctionalBlockHint;
|
|
|
|
|
extern const std::string_view ShotRules;
|
|
|
|
|
// KIND_HINTS_REPO
|
|
|
|
|
extern const std::string_view HintOutside;
|
|
|
|
|
extern const std::string_view HintAbsent;
|
feat(lenses): the commit-truth lens, repo-facts, as Gate 4
Every claim in every commit message, and in the documentation the range
adds or changes, proven or gone. The lens's block kinds are text, doc and
slot: a message unit is keyed on its text, the base and the code up to its
commit (MessageDeps); a documentation unit on its file, its normalised
text, the base and the code of the whole range (DocKeyParts); a diffstat on
its text alone; whole:order and whole:absent are asked in slot passes of
its own, never stored. A documentation file's diff header and a part the
commit writes nothing in are a mechanical n/a. Budgets 60/40 for a text or
doc block, 50/35 for a slot; one read. Gate 4, after the proofs, so the
messages and documents are read once the code they describe has settled;
the owner's gate is 5.
The goldens that follow from the lens table are derived by
tests/Goldens/derive.py, which asserts that the recorded table still
reproduces the recorded entries before it writes.
Proven, with the opt-in commit after this one: the suite (26 passed); a dry
run of a scratch range (2 commits, a README with sections) by the previous
binary and this one with the three static lenses on and the rest off, 25
prompts and 4 system files byte for byte; with repo-facts on as well,
those files unchanged and 10 passes and 1 system file added.
The lens's firing proof in this pipeline is owed (the owner's go).
2026-10-31 20:08:26 +01:00
|
|
|
// The block hints of the commit-truth lens (2026-10-31): a message unit,
|
|
|
|
|
// and a unit of a documentation file.
|
|
|
|
|
extern const std::string_view TextBlockHintRepo;
|
|
|
|
|
extern const std::string_view DocBlockHintRepo;
|
|
|
|
|
// SLOT_DUTIES: what a slot pass of a lens covers beyond the slot's
|
|
|
|
|
// question; empty for every other lens and slot.
|
|
|
|
|
std::string_view SlotDuty(std::string_view lensFile, std::string_view unitId);
|
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
|
|
|
|
|
|
|
|
// _common-repo.md with the artifact kind filled in.
|
|
|
|
|
std::string SystemText();
|
|
|
|
|
// The lens's charter, read with universal newlines.
|
|
|
|
|
std::string Charter(std::string_view lensFile);
|
|
|
|
|
|
|
|
|
|
// INPUTS, the artifact with line numbers, the inventory. trees: as they
|
|
|
|
|
// are spelled to the lens; contextPaths may be empty.
|
|
|
|
|
std::string RunLayer(std::string_view artifactRel, std::string_view base, std::string_view date, std::span<const std::string> trees, std::string_view hash,
|
|
|
|
|
std::span<const std::string> lines, const Json& units, std::span<const std::string> contextPaths = {},
|
|
|
|
|
std::string_view repoName = "the repository");
|
|
|
|
|
|
|
|
|
|
// APPLICATION UNDER TEST: what the processes of a lens with the browser
|
|
|
|
|
// environment are told about the running application — from the
|
|
|
|
|
// consumer's functional config, the login fixture the driver found and the
|
|
|
|
|
// TOTP helper's exact command. slots: the stacks are the bring-up's
|
|
|
|
|
// slots, one per pass, and this block, shared by every pass of the lens,
|
|
|
|
|
// names none of them; the pass's own is in its user message (StackText).
|
|
|
|
|
// A nullopt fixture or command prints as None.
|
|
|
|
|
std::string AppBlock(const Json& functional, const std::optional<std::string>& loginFixture = std::nullopt,
|
|
|
|
|
const std::optional<std::string>& totpCommand = std::nullopt, bool slots = false);
|
|
|
|
|
// STACK FOR THIS PASS: the slot a pass holds, in its user message, so
|
|
|
|
|
// the system prompt every pass of the lens shares stays byte-identical.
|
|
|
|
|
std::string StackText(const Json& stack, const std::optional<std::string>& totpCommand);
|
|
|
|
|
// DATABASE UNDER TEST: the exact helper command (the URL stays in the
|
|
|
|
|
// driver's broker, never here), what the driver checked before the gate
|
|
|
|
|
// (dbUser: the role of the stacks' connections, nullopt when they differ;
|
|
|
|
|
// bypass: whether that role bypasses row-level security, nullopt says
|
|
|
|
|
// nothing), what one call is, how to act as an API caller, the limits,
|
|
|
|
|
// the evidence, the owner's notes.
|
|
|
|
|
std::string DbBlock(const Json& supabase, std::string_view sqlCommand, const std::optional<std::string>& dbUser, bool withApp = false,
|
|
|
|
|
const std::optional<std::string>& checked = std::nullopt, std::optional<bool> bypass = std::nullopt);
|
|
|
|
|
// The charter, the application and database blocks when there are
|
|
|
|
|
// any, the dispositions, the whole pass's summary.
|
|
|
|
|
std::string LensLayer(std::string_view lensFile, std::string_view charterText, std::string_view dispositionsBlock, std::string_view app = {},
|
|
|
|
|
std::string_view wholeSummary = {}, std::string_view db = {});
|
|
|
|
|
// The scope of one pass: a whole pass's units, a slot's question, or a
|
|
|
|
|
// block's unit text.
|
|
|
|
|
std::string Tail(const Json& job, const Json& units, std::span<const std::string> lines, std::string_view wholeSummary = {});
|
|
|
|
|
std::string BudgetLine(const Json& job);
|
|
|
|
|
// The appended system prompt of a pass: the common charter text, the run
|
|
|
|
|
// layer and the lens layer, byte-identical for every pass of a lens in a
|
|
|
|
|
// run.
|
|
|
|
|
std::string SystemPrompt(std::string_view systemText, std::string_view run, std::string_view lens);
|
|
|
|
|
// The stdin user message of a pass: only what differs between passes. A
|
|
|
|
|
// null job adds no budget line.
|
|
|
|
|
std::string UserPrompt(std::string_view tail, const Json& job = nullptr, std::string_view stack = {});
|
|
|
|
|
}
|