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).
This commit is contained in:
Jorijn van der Graaf 2026-10-31 20:08:26 +01:00
commit febbfc3fcc
Signed by: jorijnvdgraaf
GPG key ID: 2937E59CDCC1BCFB
19 changed files with 2564 additions and 646 deletions

View file

@ -37,6 +37,25 @@ namespace Crafter::Review::Prompt {
"Judge the in-repository users and callers of what this commit changes, outside its own diff - at the base (`git -C <tree> show <base>:<path>`) and at HEAD.";
const std::string_view HintAbsent =
"Judge what a reviewer of this repository expects in this commit and does not find: a commit body at all (a body-less commit has no pK:msg unit), a test, a version or changelog bump, a doc or packaging update, an error path, a migration for existing installs.";
const std::string_view TextBlockHintRepo =
"Within this unit, verify every claim against this commit's diff and the repository at HEAD and at the base; a device, field or network claim against the evidence paths INPUTS names, or report it unverifiable.";
const std::string_view DocBlockHintRepo =
"This unit is documentation the commit adds or changes: a diff hunk of a documentation file, or one heading-delimited part of it. Judge the lines the commit adds (\"+\"): every claim in them must hold for the repository as THIS commit leaves it "
"(`git -C <tree> show <sha>:<path>`, the sha on this patch's `From` line) and, where the document at HEAD still carries it, at HEAD too - a later commit of the range may have made it false without updating it; a device, field or network claim against the evidence paths INPUTS names, or report it unverifiable. "
"Context lines are context and removed lines are not claims, except a context sentence this commit's own change makes false.";
std::string_view SlotDuty(std::string_view lensFile, std::string_view unitId) {
if (lensFile != Plan::FactsLens) return {};
if (unitId == "whole:order") {
return "; for this lens that means each message describes its own commit alone - nothing a message claims is delivered by a later commit of the range, and no message describes the state a later commit creates";
}
if (unitId == "whole:absent") {
return "; for this lens that means what the range as a whole implies but no message states - a behaviour change no message mentions, a version bump without its changelog line - "
"and documentation the range leaves stale: a sentence of the repository's README or other documentation at HEAD, written by the range or older, that the range's code makes false "
"(a behaviour, an option, a path or a command described as it was before), or a list in it that something the range adds belongs in and is missing from";
}
return {};
}
namespace {
// An optional string as the prompt prints it: None when absent.
@ -202,12 +221,14 @@ namespace Crafter::Review::Prompt {
const std::string id = Dyn::Str(Dyn::At(u, "id"));
if (kind == "slot") {
const std::string description = Dyn::Replace(Text(Dyn::At(u, "excerpt")), "FIXED SLOT: ", "");
return std::format("SCOPE - SLOT PASS, unit \"{}\": this unit has no lines; it stands for a question about the whole artifact: {}. Answer it for your lens. Coverage: exactly this one unit.\n{}",
id, description, GenericVocab);
return std::format("SCOPE - SLOT PASS, unit \"{}\": this unit has no lines; it stands for a question about the whole artifact: {}. Answer it for your lens{}. Coverage: exactly this one unit.\n{}",
id, description, SlotDuty(lensFile, id), GenericVocab);
}
const Json& range = Dyn::At(u, "lines");
const std::int64_t a = IntItem(range, 0);
const std::int64_t b = IntItem(range, 1);
const Json& unitKind = Dyn::Get(job, "unitKind");
const bool prose = unitKind == "text" || unitKind == "doc";
std::string_view hint;
if (id.ends_with(":outside")) {
hint = HintOutside;
@ -215,10 +236,15 @@ namespace Crafter::Review::Prompt {
hint = HintAbsent;
} else if (lensFile == Plan::FunctionalLens) {
hint = FunctionalBlockHint;
} else if (unitKind == "text") {
hint = TextBlockHintRepo;
} else if (unitKind == "doc") {
hint = DocBlockHintRepo;
}
const std::string text = Plan::UnitText(lines, u);
const std::string scope = std::format("SCOPE - BLOCK PASS, unit \"{}\" [lines {}-{}]: judge ONLY this unit, with your full attention by your charter - a hunk against the standard - reading the rest of the artifact only as context. Do not re-litigate the approach as a whole{}. Coverage: exactly this one unit.",
id, a, b, wholeSummary.empty() ? "" : " - the whole pass of this lens concluded as stated above");
const std::string scope = std::format("SCOPE - BLOCK PASS, unit \"{}\" [lines {}-{}]: judge ONLY this unit, with your full attention by your charter - {} - reading the rest of the artifact only as context. Do not re-litigate the approach as a whole{}. Coverage: exactly this one unit.",
id, a, b, prose ? "a claim at its source, a sentence against its proof obligation" : "a hunk against the standard",
wholeSummary.empty() ? "" : " - the whole pass of this lens concluded as stated above");
return std::format("{}{}\n\nUNIT TEXT (verbatim, lines {}-{}):\n{}\n\n{}", scope, hint.empty() ? std::string() : std::format("\n{}", hint), a, b, text, GenericVocab);
}