feat(pipeline): the pure pipeline, checked against its goldens
The modules that turn a frozen range into passes and passes into a
verdict: :Schema, :Tools (the DENY, git and base lists, a leaf, so the
config and the pool both read them), :Plan, :Artifact, :Inventory,
:Dispositions, :State, :Normalize, :Stream, :Prompt, :Config, and the URL
half of :PgWire. Units, jobs, results, the config and the claude stream
stay JSON from end to end, so every key keeps its place; :Text gives JSON
values truthiness, get, ==, membership and Str(), and throws Dyn::Error
under a name for each kind of unexpected data.
Exactness where the bytes are seen:
- the stream classifiers are hand-written scanners with case-insensitive
folds (the Kelvin sign is a k), Unicode \b and \s, and `.` stopping at
\n; the SQL call detection takes `<exe> sql` with any path before it;
- config problems carry the JSON scanner's and the UTF-8 decoder's own
texts, positions included;
- a float total is Neumaier's compensated sum, and the build passes
-ffp-contract=off: -march=native would fuse a*b+c;
- `crafter-review inventory` and `config` print what the goldens record,
byte for byte (the fixture and 14 configs, broken ones included); a
message names this binary as the command to run.
tests/Goldens: the recorded answers over the fixtures next to them (the
commits fixture, a rich versioned series with CRLF, a folded subject,
Markdown headings in and out of fences, the code-key rewrites); the suite
compares 2304 results as DumpFile writes them, so a key out of order fails
too. All agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:48:55 +01:00
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
|
|
|
|
|
|
|
|
|
module Crafter.Review:Plan_impl;
|
|
|
|
|
import :Plan;
|
|
|
|
|
import :Json;
|
|
|
|
|
import :Text;
|
|
|
|
|
import :Crypto;
|
|
|
|
|
import std;
|
|
|
|
|
|
|
|
|
|
namespace Crafter::Review::Plan {
|
|
|
|
|
namespace {
|
|
|
|
|
// The bytes of `p\d+:` at the start of a unit id, where \d is any
|
|
|
|
|
// Unicode decimal digit, as re.match reads it.
|
|
|
|
|
std::optional<std::size_t> PkPrefix(std::string_view id) {
|
|
|
|
|
if (!id.starts_with('p')) return std::nullopt;
|
|
|
|
|
const std::size_t digits = Dyn::DecimalRun(id, 1);
|
|
|
|
|
if (digits == 0 || 1 + digits >= id.size() || id[1 + digits] != ':') return std::nullopt;
|
|
|
|
|
return 2 + digits;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// group(1) of ^p\d+:(.+)#[^#]+$: the path between the prefix and the
|
|
|
|
|
// last '#', which must have something after it. `.` stops at a
|
|
|
|
|
// newline; [^#] does not.
|
|
|
|
|
std::optional<std::string_view> FileOfUnit(std::string_view id) {
|
|
|
|
|
const std::optional<std::size_t> prefix = PkPrefix(id);
|
|
|
|
|
if (!prefix) return std::nullopt;
|
|
|
|
|
const std::string_view rest = id.substr(*prefix);
|
|
|
|
|
const std::size_t hash = rest.rfind('#');
|
|
|
|
|
if (hash == std::string_view::npos || hash == 0 || hash + 1 >= rest.size()) return std::nullopt;
|
|
|
|
|
const std::string_view path = rest.substr(0, hash);
|
|
|
|
|
if (path.contains('\n')) return std::nullopt;
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IsHex(std::string_view text) {
|
|
|
|
|
return !text.empty() && std::ranges::all_of(text, [](char c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'); });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ^\d+\.\d+
|
|
|
|
|
bool StartsWithVersion(std::string_view line) {
|
|
|
|
|
const std::size_t major = Dyn::DecimalRun(line, 0);
|
|
|
|
|
if (major == 0 || major >= line.size() || line[major] != '.') return false;
|
|
|
|
|
return Dyn::DecimalRun(line, major + 1) > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ^(base-commit|prerequisite-patch-id): [0-9a-f]+$
|
|
|
|
|
bool IsTailLine(std::string_view line) {
|
|
|
|
|
for (const std::string_view head : {std::string_view("base-commit: "), std::string_view("prerequisite-patch-id: ")}) {
|
|
|
|
|
if (line.starts_with(head) && IsHex(line.substr(head.size()))) return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ^index [0-9a-f]+\.\.[0-9a-f]+( \d+)?$ -> group(1) ("" when absent)
|
|
|
|
|
std::optional<std::string_view> IndexMode(std::string_view line) {
|
|
|
|
|
if (!line.starts_with("index ")) return std::nullopt;
|
|
|
|
|
const std::string_view rest = line.substr(6);
|
|
|
|
|
const std::size_t dots = rest.find("..");
|
|
|
|
|
if (dots == std::string_view::npos || !IsHex(rest.substr(0, dots))) return std::nullopt;
|
|
|
|
|
const std::string_view after = rest.substr(dots + 2);
|
|
|
|
|
const std::size_t space = after.find(' ');
|
|
|
|
|
if (space == std::string_view::npos) {
|
|
|
|
|
if (!IsHex(after)) return std::nullopt;
|
|
|
|
|
return std::string_view();
|
|
|
|
|
}
|
|
|
|
|
if (!IsHex(after.substr(0, space))) return std::nullopt;
|
|
|
|
|
const std::string_view mode = after.substr(space);
|
|
|
|
|
if (mode.size() < 2 || Dyn::DecimalRun(mode, 1) != mode.size() - 1) return std::nullopt;
|
|
|
|
|
return mode;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// \d+(?:,\d+)? at `at`: the bytes it takes, 0 for no match.
|
|
|
|
|
std::size_t LineRange(std::string_view text, std::size_t at) {
|
|
|
|
|
const std::size_t start = Dyn::DecimalRun(text, at);
|
|
|
|
|
if (start == 0) return 0;
|
|
|
|
|
std::size_t end = at + start;
|
|
|
|
|
if (end < text.size() && text[end] == ',') {
|
|
|
|
|
const std::size_t count = Dyn::DecimalRun(text, end + 1);
|
|
|
|
|
if (count > 0) end += 1 + count;
|
|
|
|
|
}
|
|
|
|
|
return end - at;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ^@@ -\d+(?:,\d+)? \+\d+(?:,\d+)? @@(.*)$ -> group(1)
|
|
|
|
|
std::optional<std::string_view> HunkTail(std::string_view line) {
|
|
|
|
|
if (!line.starts_with("@@ -")) return std::nullopt;
|
|
|
|
|
std::size_t at = 4;
|
|
|
|
|
const std::size_t old = LineRange(line, at);
|
|
|
|
|
if (old == 0) return std::nullopt;
|
|
|
|
|
at += old;
|
|
|
|
|
if (!line.substr(at).starts_with(" +")) return std::nullopt;
|
|
|
|
|
at += 2;
|
|
|
|
|
const std::size_t now = LineRange(line, at);
|
|
|
|
|
if (now == 0) return std::nullopt;
|
|
|
|
|
at += now;
|
|
|
|
|
if (!line.substr(at).starts_with(" @@")) return std::nullopt;
|
|
|
|
|
return line.substr(at + 3);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Every line start that `head` follows: where the text is cut.
|
|
|
|
|
// Position 0 is one when the text starts with it, which makes the
|
|
|
|
|
// first piece empty.
|
|
|
|
|
std::vector<std::string> SplitBeforeLines(std::string_view text, std::string_view head) {
|
|
|
|
|
std::vector<std::size_t> cuts;
|
|
|
|
|
for (std::size_t at = 0; at <= text.size();) {
|
|
|
|
|
if (text.substr(at).starts_with(head)) cuts.push_back(at);
|
|
|
|
|
const std::size_t newline = text.find('\n', at);
|
|
|
|
|
if (newline == std::string_view::npos) break;
|
|
|
|
|
at = newline + 1;
|
|
|
|
|
}
|
|
|
|
|
std::vector<std::string> pieces;
|
|
|
|
|
std::size_t from = 0;
|
|
|
|
|
for (const std::size_t cut : cuts) {
|
|
|
|
|
pieces.emplace_back(text.substr(from, cut - from));
|
|
|
|
|
from = cut;
|
|
|
|
|
}
|
|
|
|
|
pieces.emplace_back(text.substr(from));
|
|
|
|
|
return pieces;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// re.sub(r'^Subject: (\[[^\]]*\]\s*)*', 'Subject: ', line): the
|
|
|
|
|
// `[PATCH n/m]` tags after `Subject: ` dropped, and the space after
|
|
|
|
|
// each.
|
|
|
|
|
std::string StripSubjectTags(std::string_view line) {
|
|
|
|
|
if (!line.starts_with("Subject: ")) return std::string(line);
|
|
|
|
|
std::size_t at = 9;
|
|
|
|
|
while (at < line.size() && line[at] == '[') {
|
|
|
|
|
const std::size_t close = line.find(']', at + 1);
|
|
|
|
|
if (close == std::string_view::npos) break;
|
|
|
|
|
at = close + 1;
|
|
|
|
|
at += Dyn::SpaceRun(line, at);
|
|
|
|
|
}
|
|
|
|
|
return std::format("Subject: {}", line.substr(at));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ^base-commit: [0-9a-f]{40}$
|
|
|
|
|
bool IsBaseCommit(std::string_view line) {
|
|
|
|
|
constexpr std::string_view Head = "base-commit: ";
|
|
|
|
|
return line.size() == Head.size() + 40 && line.starts_with(Head) && IsHex(line.substr(Head.size()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::int64_t IntItem(const Json& range, std::size_t index) {
|
|
|
|
|
const Json& value = range.at(index);
|
|
|
|
|
if (value.is_boolean()) return value.get<bool>() ? 1 : 0;
|
|
|
|
|
return value.get<std::int64_t>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Json Mechanical(std::string_view name, std::string_view lensFile, const Json& unit, std::string_view text, std::string_view basis) {
|
|
|
|
|
const std::string id = Dyn::At(unit, "id").get<std::string>();
|
|
|
|
|
return {
|
|
|
|
|
{"label", std::format("{}:na:{}", name, id)},
|
|
|
|
|
{"lens", name},
|
|
|
|
|
{"lensFile", lensFile},
|
|
|
|
|
{"kind", "auto-na"},
|
|
|
|
|
{"unit", id},
|
|
|
|
|
{"expectedIds", {id}},
|
|
|
|
|
{"unitSha", Sha(text)},
|
|
|
|
|
{"basis", basis},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Contains(std::span<const std::string> list, std::string_view item) {
|
|
|
|
|
return std::ranges::contains(list, item);
|
|
|
|
|
}
|
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
|
|
|
|
|
|
|
|
// any(l[:1] in ('+', '-') and l[1:].strip() for l in code_norm(text).split('\n')):
|
|
|
|
|
// does the commit add or remove a line with something on it in this
|
|
|
|
|
// part of a documentation hunk?
|
|
|
|
|
bool WritesIn(std::string_view text) {
|
|
|
|
|
for (const std::string& line : Dyn::Split(CodeNorm(text), "\n")) {
|
|
|
|
|
if ((line.starts_with('+') || line.starts_with('-')) && !Dyn::Strip(line.substr(1)).empty()) return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<ModelTier>& Models() {
|
|
|
|
|
static std::vector<ModelTier> models = {{"opus", "claude-opus-5-5"}, {"fable", "claude-opus-5-5"}};
|
|
|
|
|
return models;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::string& ModelFor(std::string_view tier) {
|
|
|
|
|
for (const ModelTier& model : Models()) {
|
|
|
|
|
if (model.tier == tier) return model.id;
|
|
|
|
|
}
|
|
|
|
|
throw Dyn::Error("KeyError", Dyn::Repr(tier));
|
|
|
|
|
}
|
|
|
|
|
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
bool IsKernelMode(std::string_view mode) {
|
|
|
|
|
return mode == "reply" || mode == "series";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::int32_t ReadsFor(std::string_view mode) {
|
|
|
|
|
return mode == "reply" ? ReplyReads : Reads;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
bool IsLens(std::string_view file) {
|
|
|
|
|
return std::ranges::any_of(Lenses, [&](const Lens& lens) { return lens.file == file; });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Lens& LensOf(std::string_view file) {
|
|
|
|
|
for (const Lens& lens : Lenses) {
|
|
|
|
|
if (lens.file == file) return lens;
|
|
|
|
|
}
|
|
|
|
|
throw Dyn::Error("KeyError", Dyn::Repr(file));
|
|
|
|
|
}
|
|
|
|
|
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
const std::vector<Gate>& Gates(std::string_view mode) {
|
|
|
|
|
static const std::vector<Gate> commits = {
|
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
|
|
|
{"Gate 1 — Approach", {"repo-better-solution.md"}},
|
|
|
|
|
{"Gate 2 — Functional", {FunctionalLens}},
|
|
|
|
|
{"Gate 3 — Proof", {"repo-bug-prover.md", "repo-security.md"}},
|
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
|
|
|
{"Gate 4 — Commit truth", {FactsLens}},
|
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
|
|
|
};
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
static const std::vector<Gate> reply = {
|
|
|
|
|
{"Gate 3 — Artifact truth", {"facts.md", "etiquette.md", "consistency.md", "conciseness.md"}},
|
|
|
|
|
};
|
|
|
|
|
static const std::vector<Gate> series = {
|
|
|
|
|
{"Gate 1 — Structure", {"better-solution.md"}},
|
|
|
|
|
{"Gate 2 — Code", {"code-quality.md", "minimalism.md", "bug-prover.md"}},
|
|
|
|
|
{"Gate 3 — Artifact truth", {"facts.md", "consistency.md", "process-docs.md", "etiquette.md", "conciseness.md"}},
|
|
|
|
|
};
|
|
|
|
|
if (mode == "reply") return reply;
|
|
|
|
|
if (mode == "series") return series;
|
|
|
|
|
if (mode == "commits") return commits;
|
|
|
|
|
throw Dyn::Error("KeyError", Dyn::Repr(mode));
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Environment* FindEnvironment(std::string_view name) {
|
|
|
|
|
for (const Environment& environment : Environments) {
|
|
|
|
|
if (environment.name == name) return &environment;
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> EnvDeps(std::string_view lensFile, std::string_view environment) {
|
|
|
|
|
const std::string_view fallback = LensOf(lensFile).env;
|
|
|
|
|
const std::string_view used = environment.empty() ? fallback : environment;
|
|
|
|
|
if (used == fallback) return {};
|
|
|
|
|
return {std::format("env={}", used)};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Budget BudgetFor(std::string_view kind, std::string_view unitKind, std::string_view lensFile) {
|
|
|
|
|
if (kind == "whole") return lensFile == FunctionalLens ? Budget{220, 120} : Budget{180, 105};
|
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
|
|
|
if (kind == "slot") return {50, 35};
|
|
|
|
|
if (unitKind == "code") return lensFile == FunctionalLens ? Budget{90, 60} : Budget{60, 40};
|
|
|
|
|
if (unitKind == "doc") return {60, 40};
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
// The facts lens of the kernel modes gets the most (2026-09-28: a
|
|
|
|
|
// facts pass on the densest unit used 58 of 60 calls and left one
|
|
|
|
|
// claim unverified).
|
|
|
|
|
if (unitKind == "text") return lensFile == "facts.md" ? Budget{80, 50} : lensFile == FactsLens ? Budget{60, 40} : Budget{50, 30};
|
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
|
|
|
throw Dyn::Error("KeyError", Dyn::Repr(std::format("block:{}", unitKind)));
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string_view DefaultEffort() {
|
|
|
|
|
return Effort;
|
|
|
|
|
}
|
|
|
|
|
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
std::string_view DefaultEffort(std::string_view mode) {
|
|
|
|
|
return IsKernelMode(mode) ? KernelEffort : Effort;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IsBareHeader(const Json& unit, std::string_view text) {
|
|
|
|
|
constexpr std::array<std::string_view, 4> Bare = {"camss-milos", "ov13b10-of", "milos-dts-camss", "across the three series"};
|
|
|
|
|
const std::string& id = Dyn::At(unit, "id").get_ref<const std::string&>();
|
|
|
|
|
return id.ends_with(":header") && std::ranges::contains(Bare, std::string_view(Dyn::Lower(Dyn::Strip(text))));
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
std::string_view UnitKindOf(std::string_view unitId) {
|
|
|
|
|
if (unitId.starts_with("whole:")) return "slot";
|
|
|
|
|
const std::optional<std::size_t> prefix = PkPrefix(unitId);
|
|
|
|
|
if (!prefix) return "text";
|
|
|
|
|
// `$` also matches before a final newline.
|
|
|
|
|
std::string_view name = unitId.substr(*prefix);
|
|
|
|
|
if (name.ends_with('\n')) name.remove_suffix(1);
|
|
|
|
|
if (name == "subject" || name == "msg" || name == "trailers" || name == "diffstat") return "text";
|
|
|
|
|
return "code";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string_view UnitKind(const Json& unit) {
|
|
|
|
|
return UnitKindOf(Dyn::At(unit, "id").get_ref<const std::string&>());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IsDocPath(std::string_view path) {
|
|
|
|
|
auto endsWithMd = [](std::string_view text) {
|
|
|
|
|
const std::u32string decoded = Dyn::Decode(text);
|
|
|
|
|
if (decoded.size() < 3) return false;
|
|
|
|
|
const std::size_t n = decoded.size();
|
|
|
|
|
return decoded[n - 3] == '.' && Dyn::IgnoreCaseLetter(decoded[n - 2]) == 'm' && Dyn::IgnoreCaseLetter(decoded[n - 1]) == 'd';
|
|
|
|
|
};
|
|
|
|
|
return endsWithMd(path) || (path.ends_with('\n') && endsWithMd(path.substr(0, path.size() - 1)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IsDocUnit(std::string_view unitId) {
|
|
|
|
|
const std::optional<std::string_view> path = FileOfUnit(unitId);
|
|
|
|
|
return path && IsDocPath(*path);
|
|
|
|
|
}
|
|
|
|
|
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
// For the repo lenses the units of a documentation file are "doc" - the
|
|
|
|
|
// commit-truth lens reads them, the code lenses do not; for the kernel
|
|
|
|
|
// lenses every unit of a diff stays code.
|
|
|
|
|
std::string_view KindFor(std::string_view lensFile, const Json& unit) {
|
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
|
|
|
const std::string_view kind = UnitKind(unit);
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
if (IsLens(lensFile) && LensOf(lensFile).kernel) return kind;
|
feat(pipeline): the pure pipeline, checked against its goldens
The modules that turn a frozen range into passes and passes into a
verdict: :Schema, :Tools (the DENY, git and base lists, a leaf, so the
config and the pool both read them), :Plan, :Artifact, :Inventory,
:Dispositions, :State, :Normalize, :Stream, :Prompt, :Config, and the URL
half of :PgWire. Units, jobs, results, the config and the claude stream
stay JSON from end to end, so every key keeps its place; :Text gives JSON
values truthiness, get, ==, membership and Str(), and throws Dyn::Error
under a name for each kind of unexpected data.
Exactness where the bytes are seen:
- the stream classifiers are hand-written scanners with case-insensitive
folds (the Kelvin sign is a k), Unicode \b and \s, and `.` stopping at
\n; the SQL call detection takes `<exe> sql` with any path before it;
- config problems carry the JSON scanner's and the UTF-8 decoder's own
texts, positions included;
- a float total is Neumaier's compensated sum, and the build passes
-ffp-contract=off: -march=native would fuse a*b+c;
- `crafter-review inventory` and `config` print what the goldens record,
byte for byte (the fixture and 14 configs, broken ones included); a
message names this binary as the command to run.
tests/Goldens: the recorded answers over the fixtures next to them (the
commits fixture, a rich versioned series with CRLF, a folded subject,
Markdown headings in and out of fences, the code-key rewrites); the suite
compares 2304 results as DumpFile writes them, so a key out of order fails
too. All agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:48:55 +01:00
|
|
|
return kind == "code" && IsDocUnit(Dyn::At(unit, "id").get_ref<const std::string&>()) ? "doc" : kind;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<std::string> UnitPath(std::string_view unitId) {
|
|
|
|
|
const std::optional<std::string_view> path = FileOfUnit(unitId);
|
|
|
|
|
if (!path) return std::nullopt;
|
|
|
|
|
return std::string(*path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> NotReviewed(const Json& units, std::span<const std::string> lines, std::span<const std::string> lensFiles,
|
|
|
|
|
std::span<const std::string> exclude) {
|
|
|
|
|
std::set<std::string> covered;
|
|
|
|
|
for (const std::string& lensFile : lensFiles) {
|
|
|
|
|
const LensPlan plan = PlanLens(lensFile, units, lines, {}, exclude);
|
|
|
|
|
if (Dyn::Truthy(plan.whole)) {
|
|
|
|
|
for (const Json& id : Dyn::At(plan.whole, "expectedIds")) covered.insert(id.get<std::string>());
|
|
|
|
|
}
|
|
|
|
|
for (const Json& block : plan.blocks) {
|
|
|
|
|
if (Dyn::At(block, "kind") != "auto-na") covered.insert(Dyn::At(block, "unit").get<std::string>());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
std::vector<std::string> out;
|
|
|
|
|
for (const Json& unit : units) {
|
|
|
|
|
const std::string& id = Dyn::At(unit, "id").get_ref<const std::string&>();
|
|
|
|
|
if (!covered.contains(id)) out.push_back(id);
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<std::string> ExcludedBy(std::string_view path, std::span<const std::string> globs) {
|
|
|
|
|
for (const std::string& glob : globs) {
|
|
|
|
|
if (Dyn::FnMatch(path, glob) || (glob.starts_with("**/") && Dyn::FnMatch(path, std::string_view(glob).substr(3)))) return glob;
|
|
|
|
|
}
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string UnitText(std::span<const std::string> lines, const Json& unit) {
|
|
|
|
|
const Json& range = Dyn::At(unit, "lines");
|
|
|
|
|
const std::int64_t a = IntItem(range, 0);
|
|
|
|
|
const std::int64_t b = IntItem(range, 1);
|
|
|
|
|
if (a == 0) return "";
|
|
|
|
|
const auto [from, to] = Dyn::SliceBounds(lines.size(), a - 1, b);
|
|
|
|
|
return Dyn::Join(lines.subspan(from, to - from), "\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string Sha(std::string_view text) {
|
|
|
|
|
return Sha256Hex(text);
|
|
|
|
|
}
|
|
|
|
|
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
std::string LensName(std::string_view lensFile, std::string_view persona) {
|
|
|
|
|
if (!persona.empty()) return std::format("persona:{}", persona);
|
feat(pipeline): the pure pipeline, checked against its goldens
The modules that turn a frozen range into passes and passes into a
verdict: :Schema, :Tools (the DENY, git and base lists, a leaf, so the
config and the pool both read them), :Plan, :Artifact, :Inventory,
:Dispositions, :State, :Normalize, :Stream, :Prompt, :Config, and the URL
half of :PgWire. Units, jobs, results, the config and the claude stream
stay JSON from end to end, so every key keeps its place; :Text gives JSON
values truthiness, get, ==, membership and Str(), and throws Dyn::Error
under a name for each kind of unexpected data.
Exactness where the bytes are seen:
- the stream classifiers are hand-written scanners with case-insensitive
folds (the Kelvin sign is a k), Unicode \b and \s, and `.` stopping at
\n; the SQL call detection takes `<exe> sql` with any path before it;
- config problems carry the JSON scanner's and the UTF-8 decoder's own
texts, positions included;
- a float total is Neumaier's compensated sum, and the build passes
-ffp-contract=off: -march=native would fuse a*b+c;
- `crafter-review inventory` and `config` print what the goldens record,
byte for byte (the fixture and 14 configs, broken ones included); a
message names this binary as the command to run.
tests/Goldens: the recorded answers over the fixtures next to them (the
commits fixture, a rich versioned series with CRLF, a folded subject,
Markdown headings in and out of fences, the code-key rewrites); the suite
compares 2304 results as DumpFile writes them, so a key out of order fails
too. All agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:48:55 +01:00
|
|
|
return Dyn::Replace(lensFile, ".md", "");
|
|
|
|
|
}
|
|
|
|
|
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
std::vector<std::string> ModeLenses(std::string_view mode) {
|
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
|
|
|
std::vector<std::string> out;
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
for (const Gate& gate : Gates(mode)) {
|
feat(pipeline): the pure pipeline, checked against its goldens
The modules that turn a frozen range into passes and passes into a
verdict: :Schema, :Tools (the DENY, git and base lists, a leaf, so the
config and the pool both read them), :Plan, :Artifact, :Inventory,
:Dispositions, :State, :Normalize, :Stream, :Prompt, :Config, and the URL
half of :PgWire. Units, jobs, results, the config and the claude stream
stay JSON from end to end, so every key keeps its place; :Text gives JSON
values truthiness, get, ==, membership and Str(), and throws Dyn::Error
under a name for each kind of unexpected data.
Exactness where the bytes are seen:
- the stream classifiers are hand-written scanners with case-insensitive
folds (the Kelvin sign is a k), Unicode \b and \s, and `.` stopping at
\n; the SQL call detection takes `<exe> sql` with any path before it;
- config problems carry the JSON scanner's and the UTF-8 decoder's own
texts, positions included;
- a float total is Neumaier's compensated sum, and the build passes
-ffp-contract=off: -march=native would fuse a*b+c;
- `crafter-review inventory` and `config` print what the goldens record,
byte for byte (the fixture and 14 configs, broken ones included); a
message names this binary as the command to run.
tests/Goldens: the recorded answers over the fixtures next to them (the
commits fixture, a rich versioned series with CRLF, a folded subject,
Markdown headings in and out of fences, the code-key rewrites); the suite
compares 2304 results as DumpFile writes them, so a key out of order fails
too. All agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:48:55 +01:00
|
|
|
for (const std::string_view lens : gate.lenses) out.emplace_back(lens);
|
|
|
|
|
}
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
if (IsKernelMode(mode)) out.emplace_back(PersonaLens);
|
feat(pipeline): the pure pipeline, checked against its goldens
The modules that turn a frozen range into passes and passes into a
verdict: :Schema, :Tools (the DENY, git and base lists, a leaf, so the
config and the pool both read them), :Plan, :Artifact, :Inventory,
:Dispositions, :State, :Normalize, :Stream, :Prompt, :Config, and the URL
half of :PgWire. Units, jobs, results, the config and the claude stream
stay JSON from end to end, so every key keeps its place; :Text gives JSON
values truthiness, get, ==, membership and Str(), and throws Dyn::Error
under a name for each kind of unexpected data.
Exactness where the bytes are seen:
- the stream classifiers are hand-written scanners with case-insensitive
folds (the Kelvin sign is a k), Unicode \b and \s, and `.` stopping at
\n; the SQL call detection takes `<exe> sql` with any path before it;
- config problems carry the JSON scanner's and the UTF-8 decoder's own
texts, positions included;
- a float total is Neumaier's compensated sum, and the build passes
-ffp-contract=off: -march=native would fuse a*b+c;
- `crafter-review inventory` and `config` print what the goldens record,
byte for byte (the fixture and 14 configs, broken ones included); a
message names this binary as the command to run.
tests/Goldens: the recorded answers over the fixtures next to them (the
commits fixture, a rich versioned series with CRLF, a folded subject,
Markdown headings in and out of fences, the code-key rewrites); the suite
compares 2304 results as DumpFile writes them, so a key out of order fails
too. All agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:48:55 +01:00
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<Gate> GatesFor(std::span<const std::string> only, std::span<const std::string> without, std::span<const std::string> off) {
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
return GatesFor("commits", only, without, off);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<Gate> GatesFor(std::string_view mode, std::span<const std::string> only, std::span<const std::string> without, std::span<const std::string> off) {
|
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
|
|
|
std::vector<Gate> out;
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
for (const Gate& gate : Gates(mode)) {
|
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
|
|
|
Gate kept{gate.title, {}};
|
|
|
|
|
for (const std::string_view lens : gate.lenses) {
|
|
|
|
|
if (!only.empty() && !Contains(only, lens)) continue;
|
|
|
|
|
if (Contains(without, lens) || Contains(off, lens)) continue;
|
|
|
|
|
kept.lenses.push_back(lens);
|
|
|
|
|
}
|
|
|
|
|
if (!kept.lenses.empty()) out.push_back(std::move(kept));
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LensPlan PlanLens(std::string_view lensFile, const Json& units, std::span<const std::string> lines, std::span<const std::string> unitsFilter,
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
std::span<const std::string> exclude, std::string_view persona, std::span<const std::string> excludeUnits) {
|
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
|
|
|
const Lens& lens = LensOf(lensFile);
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
const std::string name = LensName(lensFile, persona);
|
|
|
|
|
// A persona's jobs carry its name, after the lens file.
|
|
|
|
|
auto stamp = [&](Json job) {
|
|
|
|
|
if (persona.empty()) return job;
|
|
|
|
|
Json out = Json::object();
|
|
|
|
|
for (auto it = job.begin(); it != job.end(); ++it) {
|
|
|
|
|
out[it.key()] = it.value();
|
|
|
|
|
if (it.key() == "lensFile") out["persona"] = persona;
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
};
|
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
|
|
|
LensPlan plan;
|
|
|
|
|
if (!lens.whole.empty()) {
|
|
|
|
|
const Budget budget = BudgetFor("whole", "", lensFile);
|
|
|
|
|
Json slots = Json::array();
|
|
|
|
|
for (const Json& unit : units) {
|
|
|
|
|
const std::string& id = Dyn::At(unit, "id").get_ref<const std::string&>();
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
// A kernel lens's whole pass covers every whole:* slot of the
|
|
|
|
|
// artifact; a repo lens's the slots the table names.
|
|
|
|
|
if (UnitKind(unit) == "slot" && (lens.kernel || std::ranges::contains(lens.slots, std::string_view(id)))) slots.push_back(id);
|
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
|
|
|
}
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
plan.whole = stamp({
|
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
|
|
|
{"label", std::format("{}:whole", name)},
|
|
|
|
|
{"lens", name},
|
|
|
|
|
{"lensFile", lensFile},
|
|
|
|
|
{"kind", "whole"},
|
|
|
|
|
{"unit", nullptr},
|
|
|
|
|
{"expectedIds", slots},
|
|
|
|
|
{"model", ModelFor(lens.model)},
|
|
|
|
|
{"maxTurns", budget.maxTurns},
|
|
|
|
|
{"timeoutMin", budget.timeoutMin},
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
});
|
feat(pipeline): the pure pipeline, checked against its goldens
The modules that turn a frozen range into passes and passes into a
verdict: :Schema, :Tools (the DENY, git and base lists, a leaf, so the
config and the pool both read them), :Plan, :Artifact, :Inventory,
:Dispositions, :State, :Normalize, :Stream, :Prompt, :Config, and the URL
half of :PgWire. Units, jobs, results, the config and the claude stream
stay JSON from end to end, so every key keeps its place; :Text gives JSON
values truthiness, get, ==, membership and Str(), and throws Dyn::Error
under a name for each kind of unexpected data.
Exactness where the bytes are seen:
- the stream classifiers are hand-written scanners with case-insensitive
folds (the Kelvin sign is a k), Unicode \b and \s, and `.` stopping at
\n; the SQL call detection takes `<exe> sql` with any path before it;
- config problems carry the JSON scanner's and the UTF-8 decoder's own
texts, positions included;
- a float total is Neumaier's compensated sum, and the build passes
-ffp-contract=off: -march=native would fuse a*b+c;
- `crafter-review inventory` and `config` print what the goldens record,
byte for byte (the fixture and 14 configs, broken ones included); a
message names this binary as the command to run.
tests/Goldens: the recorded answers over the fixtures next to them (the
commits fixture, a rich versioned series with CRLF, a folded subject,
Markdown headings in and out of fences, the code-key rewrites); the suite
compares 2304 results as DumpFile writes them, so a key out of order fails
too. All agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:48:55 +01:00
|
|
|
}
|
|
|
|
|
for (const Json& unit : units) {
|
|
|
|
|
const std::string_view kind = KindFor(lensFile, unit);
|
|
|
|
|
if (!std::ranges::contains(lens.block, kind)) continue;
|
|
|
|
|
const std::string& id = Dyn::At(unit, "id").get_ref<const std::string&>();
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
if (Contains(excludeUnits, id)) continue;
|
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
|
|
|
if (!unitsFilter.empty() && !Contains(unitsFilter, id)) continue;
|
|
|
|
|
const std::string text = UnitText(lines, unit);
|
|
|
|
|
const std::optional<std::string> path = UnitPath(id);
|
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
|
|
|
if (kind == "slot") {
|
|
|
|
|
// A lens with no whole pass asks each of its own slots in a
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
// pass of its own; another lens's whole slot is not its. A
|
|
|
|
|
// kernel lens asks every whole:* slot.
|
|
|
|
|
if (!lens.kernel && !std::ranges::contains(lens.slots, std::string_view(id))) continue;
|
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
|
|
|
const Budget budget = BudgetFor("slot", "slot", lensFile);
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
plan.blocks.push_back(stamp({
|
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
|
|
|
{"label", std::format("{}:slot:{}", name, id)},
|
|
|
|
|
{"lens", name},
|
|
|
|
|
{"lensFile", lensFile},
|
|
|
|
|
{"kind", "slot"},
|
|
|
|
|
{"unit", id},
|
|
|
|
|
{"unitKind", "slot"},
|
|
|
|
|
{"expectedIds", {id}},
|
|
|
|
|
{"unitSha", Sha(text)},
|
|
|
|
|
{"model", ModelFor(lens.model)},
|
|
|
|
|
{"maxTurns", budget.maxTurns},
|
|
|
|
|
{"timeoutMin", budget.timeoutMin},
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
}));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (kind == "text" && IsBareHeader(unit, text)) {
|
|
|
|
|
plan.blocks.push_back(stamp({
|
|
|
|
|
{"label", std::format("{}:na:{}", name, id)},
|
|
|
|
|
{"lens", name},
|
|
|
|
|
{"lensFile", lensFile},
|
|
|
|
|
{"kind", "auto-na"},
|
|
|
|
|
{"unit", id},
|
|
|
|
|
{"expectedIds", {id}},
|
|
|
|
|
{"unitSha", Sha(text)},
|
|
|
|
|
}));
|
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
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (kind == "doc" && id.ends_with("#hdr")) {
|
|
|
|
|
// The diff header of a documentation file names the file, its
|
|
|
|
|
// blobs and its mode: no sentence, no claim.
|
|
|
|
|
plan.blocks.push_back(Mechanical(name, lensFile, unit, text, "mechanical: diff header of a documentation file"));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (kind == "doc" && !WritesIn(text)) {
|
|
|
|
|
// A part of a hunk that holds only context (the lines above a
|
|
|
|
|
// section the commit adds): nothing was written here.
|
|
|
|
|
plan.blocks.push_back(Mechanical(name, lensFile, unit, text, "mechanical: context only - the commit adds and removes no line in this part"));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
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
|
|
|
if (!lens.perCommitSlots && (id.ends_with(":outside") || id.ends_with(":absent"))) {
|
|
|
|
|
// The functional lens judges adjacent flows and what is missing
|
|
|
|
|
// in its whole pass, not per commit.
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (lensFile == FunctionalLens && path && id.ends_with("#hdr")) {
|
|
|
|
|
plan.blocks.push_back(Mechanical(name, lensFile, unit, text,
|
|
|
|
|
"mechanical: a diff header (mode, rename, new or deleted file) carries no behaviour of its own; the hunks of the file do"));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (lensFile == FunctionalLens && path) {
|
|
|
|
|
if (const std::optional<std::string> glob = ExcludedBy(*path, exclude)) {
|
|
|
|
|
plan.blocks.push_back(Mechanical(name, lensFile, unit, text,
|
|
|
|
|
std::format("mechanical: no runtime behaviour - the file matches functional.exclude ({})", *glob)));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const Budget budget = BudgetFor("block", kind, lensFile);
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
plan.blocks.push_back(stamp({
|
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
|
|
|
{"label", std::format("{}:block:{}", name, id)},
|
|
|
|
|
{"lens", name},
|
|
|
|
|
{"lensFile", lensFile},
|
|
|
|
|
{"kind", "block"},
|
|
|
|
|
{"unit", id},
|
|
|
|
|
{"unitKind", kind},
|
|
|
|
|
{"expectedIds", {id}},
|
|
|
|
|
{"unitSha", Sha(text)},
|
|
|
|
|
{"model", ModelFor(lens.model)},
|
|
|
|
|
{"maxTurns", budget.maxTurns},
|
|
|
|
|
{"timeoutMin", budget.timeoutMin},
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
}));
|
feat(pipeline): the pure pipeline, checked against its goldens
The modules that turn a frozen range into passes and passes into a
verdict: :Schema, :Tools (the DENY, git and base lists, a leaf, so the
config and the pool both read them), :Plan, :Artifact, :Inventory,
:Dispositions, :State, :Normalize, :Stream, :Prompt, :Config, and the URL
half of :PgWire. Units, jobs, results, the config and the claude stream
stay JSON from end to end, so every key keeps its place; :Text gives JSON
values truthiness, get, ==, membership and Str(), and throws Dyn::Error
under a name for each kind of unexpected data.
Exactness where the bytes are seen:
- the stream classifiers are hand-written scanners with case-insensitive
folds (the Kelvin sign is a k), Unicode \b and \s, and `.` stopping at
\n; the SQL call detection takes `<exe> sql` with any path before it;
- config problems carry the JSON scanner's and the UTF-8 decoder's own
texts, positions included;
- a float total is Neumaier's compensated sum, and the build passes
-ffp-contract=off: -march=native would fuse a*b+c;
- `crafter-review inventory` and `config` print what the goldens record,
byte for byte (the fixture and 14 configs, broken ones included); a
message names this binary as the command to run.
tests/Goldens: the recorded answers over the fixtures next to them (the
commits fixture, a rich versioned series with CRLF, a folded subject,
Markdown headings in and out of fences, the code-key rewrites); the suite
compares 2304 results as DumpFile writes them, so a key out of order fails
too. All agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:48:55 +01:00
|
|
|
}
|
|
|
|
|
return plan;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<std::string> ReuseKey(const Json& job, std::string_view lensFile, std::string_view unitText, std::vector<std::string> deps,
|
|
|
|
|
std::vector<std::string> inForceIds, std::string_view charterSha, std::int32_t promptVersion,
|
|
|
|
|
std::string_view ident) {
|
|
|
|
|
if (!LensOf(lensFile).reuse || Dyn::At(job, "kind") != "block") return std::nullopt;
|
|
|
|
|
std::ranges::sort(deps);
|
|
|
|
|
std::ranges::sort(inForceIds);
|
|
|
|
|
const Json& model = Dyn::Get(job, "model");
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
std::vector<std::string> parts = {
|
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
|
|
|
std::string(lensFile),
|
|
|
|
|
ident.empty() ? Dyn::At(job, "unit").get<std::string>() : std::string(ident),
|
|
|
|
|
Sha(unitText),
|
|
|
|
|
Sha(Dyn::Join(deps, "\n")),
|
|
|
|
|
Dyn::Join(inForceIds, ","),
|
|
|
|
|
std::string(charterSha),
|
|
|
|
|
std::to_string(promptVersion),
|
|
|
|
|
Dyn::Has(job, "model") ? model.get<std::string>() : std::string(),
|
|
|
|
|
std::string(ReuseKeyEffortSlot),
|
|
|
|
|
};
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
if (Dyn::Truthy(Dyn::Get(job, "persona"))) parts.push_back(std::format("persona={}", Dyn::Str(job.at("persona"))));
|
feat(pipeline): the pure pipeline, checked against its goldens
The modules that turn a frozen range into passes and passes into a
verdict: :Schema, :Tools (the DENY, git and base lists, a leaf, so the
config and the pool both read them), :Plan, :Artifact, :Inventory,
:Dispositions, :State, :Normalize, :Stream, :Prompt, :Config, and the URL
half of :PgWire. Units, jobs, results, the config and the claude stream
stay JSON from end to end, so every key keeps its place; :Text gives JSON
values truthiness, get, ==, membership and Str(), and throws Dyn::Error
under a name for each kind of unexpected data.
Exactness where the bytes are seen:
- the stream classifiers are hand-written scanners with case-insensitive
folds (the Kelvin sign is a k), Unicode \b and \s, and `.` stopping at
\n; the SQL call detection takes `<exe> sql` with any path before it;
- config problems carry the JSON scanner's and the UTF-8 decoder's own
texts, positions included;
- a float total is Neumaier's compensated sum, and the build passes
-ffp-contract=off: -march=native would fuse a*b+c;
- `crafter-review inventory` and `config` print what the goldens record,
byte for byte (the fixture and 14 configs, broken ones included); a
message names this binary as the command to run.
tests/Goldens: the recorded answers over the fixtures next to them (the
commits fixture, a rich versioned series with CRLF, a folded subject,
Markdown headings in and out of fences, the code-key rewrites); the suite
compares 2304 results as DumpFile writes them, so a key out of order fails
too. All agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:48:55 +01:00
|
|
|
return Sha(Dyn::Join(parts, "|")).substr(0, 16);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string CodeNorm(std::string_view text) {
|
|
|
|
|
std::vector<std::string> lines = Dyn::Split(text, "\n");
|
|
|
|
|
while (!lines.empty() && lines.back().empty()) lines.pop_back();
|
|
|
|
|
if (lines.size() >= 2 && lines[lines.size() - 2] == "-- " && StartsWithVersion(lines.back())) {
|
|
|
|
|
lines.resize(lines.size() - 2);
|
|
|
|
|
while (!lines.empty() && (lines.back().empty() || IsTailLine(lines.back()))) lines.pop_back();
|
|
|
|
|
}
|
|
|
|
|
for (std::string& line : lines) {
|
|
|
|
|
if (const std::optional<std::string_view> mode = IndexMode(line)) {
|
|
|
|
|
line = std::format("index{}", *mode);
|
|
|
|
|
} else if (const std::optional<std::string_view> tail = HunkTail(line)) {
|
|
|
|
|
line = std::format("@@{}", *tail);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Dyn::Join(lines, "\n");
|
|
|
|
|
}
|
|
|
|
|
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
PatchParts PartsOf(std::string_view patchText, bool docFiles) {
|
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
|
|
|
const std::vector<std::string> lines = Dyn::Split(patchText, "\n");
|
|
|
|
|
std::optional<std::size_t> subject;
|
|
|
|
|
for (std::size_t i = 0; i < lines.size(); ++i) {
|
|
|
|
|
if (lines[i].starts_with("Subject:")) {
|
|
|
|
|
subject = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
std::size_t body0 = 1;
|
|
|
|
|
if (subject) {
|
|
|
|
|
for (std::size_t i = *subject + 1; i < lines.size(); ++i) {
|
|
|
|
|
if (Dyn::Strip(lines[i]).empty()) {
|
|
|
|
|
body0 = i + 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
std::size_t diff0 = lines.size();
|
|
|
|
|
for (std::size_t i = body0; i < lines.size(); ++i) {
|
|
|
|
|
if (lines[i].starts_with("---")) {
|
|
|
|
|
diff0 = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
std::size_t first = lines.size();
|
|
|
|
|
for (std::size_t i = diff0 + 1; i < lines.size(); ++i) {
|
|
|
|
|
if (lines[i].starts_with("diff --git")) {
|
|
|
|
|
first = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
PatchParts parts;
|
|
|
|
|
for (const std::string& line : lines) {
|
|
|
|
|
if (IsBaseCommit(line)) {
|
|
|
|
|
parts.base = Dyn::Split(line)[1];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const std::span<const std::string> code(lines.begin() + static_cast<std::ptrdiff_t>(std::min(first, lines.size())), lines.end());
|
|
|
|
|
for (const std::string& section : SplitBeforeLines(CodeNorm(Dyn::Join(code, "\n")), "diff --git ")) {
|
|
|
|
|
const std::string firstLine = Dyn::Split(section, "\n", 1)[0];
|
|
|
|
|
const std::string path = Dyn::Strip(Dyn::Split(firstLine, " b/").back());
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
if (docFiles && section.starts_with("diff --git ") && IsDocPath(path)) {
|
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
|
|
|
// re.split(r'(?m)^@@', section, maxsplit=1)[0].rstrip('\n')
|
|
|
|
|
std::size_t header = section.size();
|
|
|
|
|
for (std::size_t at = 0; at < section.size();) {
|
|
|
|
|
if (std::string_view(section).substr(at).starts_with("@@")) {
|
|
|
|
|
header = at;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
const std::size_t newline = section.find('\n', at);
|
|
|
|
|
if (newline == std::string::npos) break;
|
|
|
|
|
at = newline + 1;
|
|
|
|
|
}
|
|
|
|
|
parts.docs.push_back(Dyn::RStrip(std::string_view(section).substr(0, header), "\n"));
|
|
|
|
|
} else {
|
|
|
|
|
parts.code += section;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
std::ranges::sort(parts.docs);
|
|
|
|
|
const auto [messageFrom, messageTo] = Dyn::SliceBounds(lines.size(), static_cast<std::int64_t>(subject ? *subject : body0), static_cast<std::int64_t>(diff0));
|
|
|
|
|
std::vector<std::string> message;
|
|
|
|
|
for (std::size_t i = messageFrom; i < messageTo; ++i) message.push_back(StripSubjectTags(lines[i]));
|
|
|
|
|
parts.message = Dyn::Join(message, "\n");
|
|
|
|
|
const auto [bodyFrom, bodyTo] = Dyn::SliceBounds(lines.size(), static_cast<std::int64_t>(body0), static_cast<std::int64_t>(diff0));
|
|
|
|
|
for (std::size_t i = bodyFrom; i < bodyTo; ++i) {
|
|
|
|
|
if (!Dyn::Strip(lines[i]).empty()) {
|
|
|
|
|
parts.hasBody = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return parts;
|
|
|
|
|
}
|
|
|
|
|
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
CommitCode CommitCodeOf(const std::map<std::int64_t, std::string>& patches, bool kernel) {
|
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
|
|
|
CommitCode cc;
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
cc.kernel = kernel;
|
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
|
|
|
std::set<std::string> bases;
|
|
|
|
|
std::vector<std::string> codes;
|
|
|
|
|
for (const auto& [k, text] : patches) {
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
PatchParts parts = PartsOf(text, !kernel);
|
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
|
|
|
cc.body[k] = parts.hasBody;
|
|
|
|
|
cc.code[k] = Sha(parts.code);
|
|
|
|
|
cc.docs[k] = std::move(parts.docs);
|
|
|
|
|
cc.message[k] = Sha(parts.message);
|
|
|
|
|
if (!parts.base.empty()) bases.insert(parts.base);
|
|
|
|
|
codes.push_back(cc.code[k]);
|
|
|
|
|
cc.upto[k] = Sha(Dyn::Join(codes, "\n"));
|
|
|
|
|
}
|
|
|
|
|
cc.range = Sha(Dyn::Join(codes, "\n"));
|
|
|
|
|
cc.base = Dyn::Join(std::vector<std::string>(bases.begin(), bases.end()), ",");
|
|
|
|
|
return cc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::pair<std::string, std::vector<std::string>> CodeKeyParts(std::string_view unitId, const CommitCode& cc) {
|
|
|
|
|
const std::size_t colon = unitId.find(':');
|
|
|
|
|
if (colon == std::string_view::npos) throw Dyn::Error("ValueError", "not enough values to unpack (expected 2, got 1)");
|
|
|
|
|
const std::string_view pk = unitId.substr(0, colon);
|
|
|
|
|
const std::string_view rest = unitId.substr(colon + 1);
|
|
|
|
|
const std::string_view number = pk.empty() ? pk : pk.substr(1);
|
|
|
|
|
const std::optional<std::int64_t> k = Dyn::ParseInt(number);
|
|
|
|
|
if (!k) throw Dyn::Error("ValueError", Dyn::IntError(number));
|
|
|
|
|
std::vector<std::string> deps = {std::format("base={}", cc.base)};
|
|
|
|
|
if (rest == "outside" || rest == "absent") {
|
|
|
|
|
const auto code = cc.code.find(*k);
|
|
|
|
|
if (code == cc.code.end()) throw Dyn::Error("KeyError", std::to_string(*k));
|
|
|
|
|
deps.push_back(std::format("commit={}:{}", *k, code->second));
|
|
|
|
|
deps.push_back(std::format("range={}", cc.range));
|
|
|
|
|
deps.push_back(std::format("docs={}", Dyn::Join(cc.docs.at(*k), "|")));
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
// A kernel reviewer looks for a trailer, a Cc, a test statement:
|
|
|
|
|
// the patch's message is what `absent` depends on there; in an
|
|
|
|
|
// own repository it looks for a body at all.
|
|
|
|
|
if (rest == "absent") deps.push_back(cc.kernel ? std::format("msg={}", cc.message.at(*k)) : std::format("body={}", cc.body.at(*k) ? "yes" : "no"));
|
feat(pipeline): the pure pipeline, checked against its goldens
The modules that turn a frozen range into passes and passes into a
verdict: :Schema, :Tools (the DENY, git and base lists, a leaf, so the
config and the pool both read them), :Plan, :Artifact, :Inventory,
:Dispositions, :State, :Normalize, :Stream, :Prompt, :Config, and the URL
half of :PgWire. Units, jobs, results, the config and the claude stream
stay JSON from end to end, so every key keeps its place; :Text gives JSON
values truthiness, get, ==, membership and Str(), and throws Dyn::Error
under a name for each kind of unexpected data.
Exactness where the bytes are seen:
- the stream classifiers are hand-written scanners with case-insensitive
folds (the Kelvin sign is a k), Unicode \b and \s, and `.` stopping at
\n; the SQL call detection takes `<exe> sql` with any path before it;
- config problems carry the JSON scanner's and the UTF-8 decoder's own
texts, positions included;
- a float total is Neumaier's compensated sum, and the build passes
-ffp-contract=off: -march=native would fuse a*b+c;
- `crafter-review inventory` and `config` print what the goldens record,
byte for byte (the fixture and 14 configs, broken ones included); a
message names this binary as the command to run.
tests/Goldens: the recorded answers over the fixtures next to them (the
commits fixture, a rich versioned series with CRLF, a folded subject,
Markdown headings in and out of fences, the code-key rewrites); the suite
compares 2304 results as DumpFile writes them, so a key out of order fails
too. All agree.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 06:48:55 +01:00
|
|
|
return {std::format("code:{}", rest), deps};
|
|
|
|
|
}
|
|
|
|
|
const std::size_t hash = rest.rfind('#');
|
|
|
|
|
if (hash == std::string_view::npos) throw Dyn::Error("ValueError", "not enough values to unpack (expected 2, got 1)");
|
|
|
|
|
const std::string_view tag = rest.substr(hash + 1);
|
|
|
|
|
return {std::format("code:{}#{}", rest.substr(0, hash), tag == "hdr" ? "hdr" : "hunk"), deps};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<std::string> CodeReuseKey(const Json& job, std::string_view lensFile, std::string_view unitText, const CommitCode& cc,
|
|
|
|
|
std::span<const std::string> inForceIds, std::string_view charterSha, std::int32_t promptVersion,
|
|
|
|
|
std::string_view environment) {
|
|
|
|
|
auto [ident, deps] = CodeKeyParts(Dyn::At(job, "unit").get_ref<const std::string&>(), cc);
|
|
|
|
|
std::ranges::move(EnvDeps(lensFile, environment), std::back_inserter(deps));
|
|
|
|
|
return ReuseKey(job, lensFile, CodeNorm(unitText), deps, {inForceIds.begin(), inForceIds.end()}, charterSha, promptVersion, ident);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<std::string> FunctionalReuseKey(const Json& job, std::string_view lensFile, std::string_view unitText, const CommitCode& cc,
|
|
|
|
|
std::span<const std::string> inForceIds, std::string_view charterSha, std::int32_t promptVersion,
|
|
|
|
|
std::string_view environment) {
|
|
|
|
|
auto [ident, deps] = CodeKeyParts(Dyn::At(job, "unit").get_ref<const std::string&>(), cc);
|
|
|
|
|
deps.push_back(std::format("range={}", cc.range));
|
|
|
|
|
std::ranges::move(EnvDeps(lensFile, environment), std::back_inserter(deps));
|
|
|
|
|
return ReuseKey(job, lensFile, CodeNorm(unitText), deps, {inForceIds.begin(), inForceIds.end()}, charterSha, promptVersion,
|
|
|
|
|
std::format("functional:{}", ident));
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
std::pair<std::string, std::vector<std::string>> DocKeyParts(std::string_view unitId, const CommitCode& cc) {
|
|
|
|
|
const std::size_t colon = unitId.find(':');
|
|
|
|
|
if (colon == std::string_view::npos) throw Dyn::Error("ValueError", "not enough values to unpack (expected 2, got 1)");
|
|
|
|
|
const std::string_view rest = unitId.substr(colon + 1);
|
|
|
|
|
const std::size_t hash = rest.rfind('#');
|
|
|
|
|
return {std::format("doc:{}", hash == std::string_view::npos ? rest : rest.substr(0, hash)), {std::format("base={}", cc.base), std::format("range={}", cc.range)}};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> MessageDeps(std::string_view unitId, const CommitCode& cc) {
|
|
|
|
|
// ^p(\d+):(subject|msg)$; `$` also matches before a final newline.
|
|
|
|
|
const std::optional<std::size_t> prefix = PkPrefix(unitId);
|
|
|
|
|
if (!prefix) return {};
|
|
|
|
|
std::string_view name = unitId.substr(*prefix);
|
|
|
|
|
if (name.ends_with('\n')) name.remove_suffix(1);
|
|
|
|
|
if (name != "subject" && name != "msg") return {};
|
|
|
|
|
const std::string_view number = unitId.substr(1, *prefix - 2);
|
|
|
|
|
const std::optional<std::int64_t> k = Dyn::ParseInt(number);
|
|
|
|
|
if (!k) throw Dyn::Error("ValueError", Dyn::IntError(number));
|
|
|
|
|
const auto upto = cc.upto.find(*k);
|
|
|
|
|
if (upto == cc.upto.end()) throw Dyn::Error("KeyError", std::to_string(*k));
|
|
|
|
|
return {std::format("base={}", cc.base), std::format("upto={}", upto->second)};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<std::string> DocReuseKey(const Json& job, std::string_view lensFile, std::string_view unitText, const CommitCode& cc,
|
|
|
|
|
std::span<const std::string> inForceIds, std::string_view charterSha, std::int32_t promptVersion,
|
|
|
|
|
std::string_view environment) {
|
|
|
|
|
auto [ident, deps] = DocKeyParts(Dyn::At(job, "unit").get_ref<const std::string&>(), cc);
|
|
|
|
|
std::ranges::move(EnvDeps(lensFile, environment), std::back_inserter(deps));
|
|
|
|
|
return ReuseKey(job, lensFile, CodeNorm(unitText), deps, {inForceIds.begin(), inForceIds.end()}, charterSha, promptVersion, ident);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<std::string> TextReuseKey(const Json& job, std::string_view lensFile, std::string_view unitText, const CommitCode& cc,
|
|
|
|
|
std::span<const std::string> inForceIds, std::string_view charterSha, std::int32_t promptVersion,
|
|
|
|
|
std::string_view environment) {
|
|
|
|
|
std::vector<std::string> deps = MessageDeps(Dyn::At(job, "unit").get_ref<const std::string&>(), cc);
|
|
|
|
|
std::ranges::move(EnvDeps(lensFile, environment), std::back_inserter(deps));
|
|
|
|
|
return ReuseKey(job, lensFile, unitText, deps, {inForceIds.begin(), inForceIds.end()}, charterSha, promptVersion);
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
std::optional<std::string> BlockReuseKey(const Json& job, std::string_view lensFile, std::string_view unitText, const CommitCode& cc,
|
|
|
|
|
std::span<const std::string> inForceIds, std::string_view charterSha, std::int32_t promptVersion,
|
|
|
|
|
std::string_view environment) {
|
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
|
|
|
// A slot pass and a whole pass have no block key (ReuseKey's own
|
|
|
|
|
// rule, before any id is parsed: a `whole:*` id has no commit number).
|
|
|
|
|
if (Dyn::At(job, "kind") != "block") return std::nullopt;
|
|
|
|
|
const Json& unitKind = Dyn::Get(job, "unitKind");
|
|
|
|
|
if (unitKind == "doc") return DocReuseKey(job, lensFile, unitText, cc, inForceIds, charterSha, promptVersion, environment);
|
|
|
|
|
if (unitKind == "text") return TextReuseKey(job, lensFile, unitText, cc, inForceIds, charterSha, promptVersion, environment);
|
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
|
|
|
if (LensOf(lensFile).key == "functional") {
|
|
|
|
|
return FunctionalReuseKey(job, lensFile, unitText, cc, inForceIds, charterSha, promptVersion, environment);
|
|
|
|
|
}
|
|
|
|
|
return CodeReuseKey(job, lensFile, unitText, cc, inForceIds, charterSha, promptVersion, environment);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<std::string> WholeCodeKey(const Json& job, std::string_view lensFile, const CommitCode& cc, std::span<const std::string> inForceIds,
|
|
|
|
|
std::string_view charterSha, std::int32_t promptVersion, std::string_view environment) {
|
|
|
|
|
if (!LensOf(lensFile).wholeReuse || Dyn::At(job, "kind") != "whole") return std::nullopt;
|
|
|
|
|
std::string body;
|
|
|
|
|
for (const auto& [k, has] : cc.body) {
|
|
|
|
|
if (!body.empty()) body.push_back(',');
|
|
|
|
|
body.push_back(has ? 'y' : 'n');
|
|
|
|
|
}
|
|
|
|
|
std::vector<std::string> docs;
|
|
|
|
|
for (const auto& [k, files] : cc.docs) docs.push_back(Dyn::Join(files, "|"));
|
|
|
|
|
std::vector<std::string> deps = {
|
|
|
|
|
std::format("base={}", cc.base),
|
|
|
|
|
std::format("range={}", cc.range),
|
|
|
|
|
std::format("body={}", body),
|
|
|
|
|
std::format("docs={}", Dyn::Join(docs, ";")),
|
|
|
|
|
};
|
|
|
|
|
std::ranges::move(EnvDeps(lensFile, environment), std::back_inserter(deps));
|
|
|
|
|
std::vector<std::string> ids(inForceIds.begin(), inForceIds.end());
|
|
|
|
|
std::ranges::sort(ids);
|
|
|
|
|
const std::vector<std::string> parts = {
|
|
|
|
|
std::string(lensFile),
|
|
|
|
|
"code:whole",
|
|
|
|
|
Sha(Dyn::Join(deps, "\n")),
|
|
|
|
|
Dyn::Join(ids, ","),
|
|
|
|
|
std::string(charterSha),
|
|
|
|
|
std::to_string(promptVersion),
|
|
|
|
|
Dyn::Has(job, "model") ? Dyn::Get(job, "model").get<std::string>() : std::string(),
|
|
|
|
|
std::string(ReuseKeyEffortSlot),
|
|
|
|
|
};
|
|
|
|
|
return Sha(Dyn::Join(parts, "|")).substr(0, 16);
|
|
|
|
|
}
|
|
|
|
|
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
namespace {
|
|
|
|
|
// \b before `at` and after `end` in the decoded text.
|
|
|
|
|
bool Bounded(const std::u32string& text, std::size_t at, std::size_t end) {
|
|
|
|
|
const bool before = at == 0 || !Dyn::IsWord(text[at - 1]);
|
|
|
|
|
const bool after = end >= text.size() || !Dyn::IsWord(text[end]);
|
|
|
|
|
return before && after;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A phrase at `at`, letters compared without case.
|
|
|
|
|
bool PhraseAt(const std::u32string& text, std::size_t at, std::string_view phrase) {
|
|
|
|
|
if (at + phrase.size() > text.size()) return false;
|
|
|
|
|
for (std::size_t i = 0; i < phrase.size(); ++i) {
|
|
|
|
|
const char32_t c = text[at + i];
|
|
|
|
|
const char p = phrase[i];
|
|
|
|
|
if (p >= 'a' && p <= 'z') {
|
|
|
|
|
if (Dyn::IgnoreCaseLetter(c) != p) return false;
|
|
|
|
|
} else if (c != static_cast<char32_t>(p)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// re.search(r'\d{4}-\d{2}-\d{2}|\bv\d+\b|\bas of\b|...', text, re.I)
|
|
|
|
|
bool Dated(std::string_view unitText) {
|
|
|
|
|
constexpr std::array<std::string_view, 9> Words = {"as of", "still", "unmerged", "in review", "no reply", "latest", "merged", "posted", "applied"};
|
|
|
|
|
const std::u32string text = Dyn::Decode(unitText);
|
|
|
|
|
auto digits = [&](std::size_t at, std::size_t n) {
|
|
|
|
|
for (std::size_t i = 0; i < n; ++i) {
|
|
|
|
|
if (at + i >= text.size() || !Dyn::IsDecimal(text[at + i])) return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
};
|
|
|
|
|
for (std::size_t at = 0; at < text.size(); ++at) {
|
|
|
|
|
if (digits(at, 4) && at + 4 < text.size() && text[at + 4] == '-' && digits(at + 5, 2) && at + 7 < text.size() && text[at + 7] == '-' && digits(at + 8, 2)) return true;
|
|
|
|
|
if (Dyn::IgnoreCaseLetter(text[at]) == 'v' && at + 1 < text.size() && Dyn::IsDecimal(text[at + 1])) {
|
|
|
|
|
std::size_t end = at + 1;
|
|
|
|
|
while (end < text.size() && Dyn::IsDecimal(text[end])) ++end;
|
|
|
|
|
if (Bounded(text, at, end)) return true;
|
|
|
|
|
}
|
|
|
|
|
for (const std::string_view word : Words) {
|
|
|
|
|
if (PhraseAt(text, at, word) && Bounded(text, at, at + word.size())) return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// re.fullmatch(r'R\d+', id)
|
|
|
|
|
bool IsReversalId(std::string_view id) {
|
|
|
|
|
return id.size() > 1 && id[0] == 'R' && Dyn::DecimalRun(id, 1) == id.size() - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// re.search(r'\b' + re.escape(id) + r'\b', text)
|
|
|
|
|
bool NamesUnit(std::string_view unitText, std::string_view id) {
|
|
|
|
|
const std::u32string text = Dyn::Decode(unitText);
|
|
|
|
|
const std::u32string needle = Dyn::Decode(id);
|
|
|
|
|
for (std::size_t at = 0; at + needle.size() <= text.size(); ++at) {
|
|
|
|
|
if (std::u32string_view(text).substr(at, needle.size()) == needle && Bounded(text, at, at + needle.size())) return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> TextDeps(std::string_view unitText, const Json& units, std::span<const std::string> lines, std::span<const std::pair<std::string, std::string>> refs,
|
|
|
|
|
std::string_view anchorText) {
|
|
|
|
|
std::vector<std::string> deps;
|
|
|
|
|
// sorted(set(int(x) for x in re.findall(r'\[(\d+)\]', text)))
|
|
|
|
|
std::set<std::int64_t> cited;
|
|
|
|
|
for (std::size_t at = 0; at < unitText.size(); ++at) {
|
|
|
|
|
if (unitText[at] != '[') continue;
|
|
|
|
|
const std::size_t digits = Dyn::DecimalRun(unitText, at + 1);
|
|
|
|
|
if (digits == 0 || at + 1 + digits >= unitText.size() || unitText[at + 1 + digits] != ']') continue;
|
|
|
|
|
if (const std::optional<std::int64_t> n = Dyn::ParseInt(unitText.substr(at + 1, digits))) cited.insert(*n);
|
|
|
|
|
at += digits + 1;
|
|
|
|
|
}
|
|
|
|
|
for (const std::int64_t n : cited) {
|
|
|
|
|
std::string url = "?";
|
|
|
|
|
for (const auto& [key, value] : refs) {
|
|
|
|
|
if (key == std::to_string(n)) url = value;
|
|
|
|
|
}
|
|
|
|
|
deps.push_back(std::format("ref[{}]={}", n, url));
|
|
|
|
|
}
|
|
|
|
|
if (Dated(unitText)) deps.push_back(std::format("anchor={}", Sha(anchorText)));
|
|
|
|
|
for (const Json& unit : units) {
|
|
|
|
|
const std::string& id = Dyn::At(unit, "id").get_ref<const std::string&>();
|
|
|
|
|
if (IsReversalId(id) && NamesUnit(unitText, id)) deps.push_back(std::format("unit[{}]={}", id, Sha(UnitText(lines, unit))));
|
|
|
|
|
}
|
|
|
|
|
return deps;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
std::int64_t ReadsOf(const Json& entry) {
|
|
|
|
|
if (!Dyn::Truthy(entry)) return 0;
|
|
|
|
|
const Json& reads = Dyn::Get(entry, "reads");
|
|
|
|
|
if (!Dyn::Truthy(reads)) return 1;
|
|
|
|
|
if (reads.is_string()) return static_cast<std::int64_t>(Dyn::Length(reads.get_ref<const std::string&>()));
|
|
|
|
|
return static_cast<std::int64_t>(reads.size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ReadIn(const Json& entry, std::string_view hash8, std::int64_t round) {
|
|
|
|
|
const Json& reads = Dyn::Or(Dyn::Get(entry, "reads"), Dyn::EmptyList());
|
|
|
|
|
return std::ranges::any_of(reads, [&](const Json& read) {
|
|
|
|
|
return Dyn::Equal(Dyn::Get(read, "hash"), Json(hash8)) && Dyn::Equal(Dyn::Get(read, "round"), Json(round));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Json Rebind(const Json& entry, std::string_view unitId) {
|
|
|
|
|
Json out = entry;
|
|
|
|
|
out["unit"] = unitId;
|
|
|
|
|
Json coverage = Dyn::At(out, "coverage");
|
|
|
|
|
if (!coverage.is_object()) throw Dyn::Error("TypeError", std::format("'{}' object is not iterable", Dyn::TypeName(coverage)));
|
|
|
|
|
coverage["item"] = unitId;
|
|
|
|
|
out["coverage"] = std::move(coverage);
|
|
|
|
|
for (const std::string_view field : {std::string_view("findings"), std::string_view("notes")}) {
|
|
|
|
|
if (!Dyn::Has(out, field)) continue;
|
|
|
|
|
for (Json& item : out[std::string(field)]) {
|
|
|
|
|
if (Dyn::Get(item, "items").is_array()) item["items"] = Json::array({unitId});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Json Estimate(std::span<const Json> jobs, std::int64_t prefixBytes, const std::map<std::string, std::int64_t>& lensLayerBytes,
|
|
|
|
|
std::int64_t tailBytes, double tpb, std::int64_t sysTokens, std::int64_t outPerTurn) {
|
|
|
|
|
const double prefix = static_cast<double>(prefixBytes) / tpb + static_cast<double>(sysTokens);
|
|
|
|
|
double cacheRead = 0.0;
|
|
|
|
|
double cacheWrite = 0.0;
|
|
|
|
|
double output = 0.0;
|
|
|
|
|
std::int64_t processes = 0;
|
|
|
|
|
std::set<std::pair<std::string, std::string>> seen;
|
|
|
|
|
for (const Json& job : jobs) {
|
|
|
|
|
const std::string kind = Dyn::At(job, "kind").get<std::string>();
|
|
|
|
|
if (kind == "auto-na") continue;
|
|
|
|
|
const std::string lens = Dyn::At(job, "lens").get<std::string>();
|
|
|
|
|
const auto layer = lensLayerBytes.find(lens);
|
|
|
|
|
const double lensTokens = static_cast<double>(layer == lensLayerBytes.end() ? 3000 : layer->second) / tpb;
|
|
|
|
|
const double tail = static_cast<double>(tailBytes) / tpb;
|
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
|
|
|
const Json& unitKind = Dyn::Get(job, "unitKind");
|
feat(modes): the kernel modes - a patch series and a mailing-list reply
Beside the push gates, crafter-review runs the pre-send review of a kernel
contributor's workbench: --mode series over a format-patch export with its
cover letter, --mode reply over a mail draft. The inventory partitions a
cover letter, a plain mail and the camera review's shape; ten kernel lenses
join the table with their gates (structure, code, artifact truth) and the
persona gate - one maintainer-persona instance per --reviewers entry, its
whole pass gating its blocks and pruning the units that are not theirs. A
series' code units are keyed on the code like the push gates'; every text
unit on its text, the references it cites and the anchor when it is dated.
The references an artifact cites are prefetched through utilities/lore.py
into the gate-state, with a digest in the run layer, and a persona's
calibration map is its lore listing. The kernel schema carries the persona
vocabulary, the kernel note kinds, the predicted review and the not-mine
list; the matrix the persona holes, the thin and the modelled units; gates
clean without a persona pass is GATES CLEAN. A reply's gate-state sits
beside the draft and is read once; a kernel mode needs --subsystem,
defaults the effort to max and the trees to work/linux,work/milos-linux,
and excuses no unit from the holes.
The kernel lenses and the common text ship verbatim; the table lists them
after the push gates' lenses and the config template holds them off, so a
repository that never turns them on changes nothing. Prompts, keys and plans
were checked byte for byte against the pipeline these modes replace, on its
own artifacts: two replies and a series, every system prompt, user prompt,
job and reuse key identical.
2026-10-31 22:56:12 +01:00
|
|
|
const Json& lensFile = Dyn::At(job, "lensFile");
|
|
|
|
|
const std::int64_t turns = kind == "whole" ? 40 : kind == "slot" ? 10 : lensFile == FunctionalLens ? 25
|
|
|
|
|
: unitKind == "code" ? 10 : (lensFile == FactsLens || lensFile == "facts.md" ? 12 : 8);
|
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
|
|
|
if (seen.insert({lens, kind}).second) cacheWrite += prefix + lensTokens;
|
|
|
|
|
cacheWrite += tail + static_cast<double>(turns * 3000);
|
|
|
|
|
std::vector<double> reads;
|
|
|
|
|
for (std::int64_t i = 0; i < turns; ++i) reads.push_back(prefix + lensTokens + tail + static_cast<double>(3000 * i));
|
|
|
|
|
cacheRead += Dyn::Sum(reads);
|
|
|
|
|
output += static_cast<double>(turns * outPerTurn);
|
|
|
|
|
++processes;
|
|
|
|
|
}
|
|
|
|
|
const double costUnits = 1.25 * cacheWrite + 0.1 * cacheRead + 5.0 * output;
|
|
|
|
|
const double listUsd = Dyn::Round((6.25 * cacheWrite + 0.5 * cacheRead + 25.0 * output) / 1e6, 2);
|
|
|
|
|
return {
|
|
|
|
|
{"cacheRead", cacheRead},
|
|
|
|
|
{"cacheWrite", cacheWrite},
|
|
|
|
|
{"output", output},
|
|
|
|
|
{"processes", processes},
|
|
|
|
|
{"costUnits", costUnits},
|
|
|
|
|
{"listUsd", listUsd},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|