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.
This commit is contained in:
parent
4fc15fe1c2
commit
339f4b9b40
46 changed files with 5732 additions and 362 deletions
|
|
@ -16,6 +16,33 @@ namespace Crafter::Review::Prompt {
|
|||
"defect (a finding with items:[id] exists), immaterial (a note kind=immaterial with items:[id] exists), n/a (the unit carries nothing your charter judges - the basis says why). "
|
||||
"For the functional lens \"clear\" means the behaviour of the unit was exercised in the running application and observed as the code intends, never read as plausible; a unit with no reachable behaviour is n/a with the reason, and a behaviour you could not reach for a reason that is not by design is an `unverified` note with n/a, never clear.";
|
||||
|
||||
const std::string_view GenericVocabKernel =
|
||||
"Coverage vocabulary for this lens: clear (you checked this unit by your charter and found nothing - the basis says what you checked it against: the source fetched, the tree ref, the units you crossed it with), "
|
||||
"defect (a finding with items:[id] exists), immaterial (a note kind=immaterial with items:[id] exists), n/a (the unit carries nothing your charter judges - the basis says why; a paragraph of claims is never n/a). "
|
||||
"For the facts lens \"clear\" means every claim in the unit was checked at its source, not read as plausible; for the consistency lens the basis names the unit ids crossed; for the conciseness lens the basis names the class that keeps each sentence.";
|
||||
const std::string_view PersonaVocab =
|
||||
"Coverage vocabulary for a maintainer or reviewer: would-require (you would ask for this yourself), no-comment, would-object (you would push back - a finding with items:[id] must exist), incomplete (the unit is right but misses what a fix must contain - finding required), not-mine (not your tree, file or decision). "
|
||||
"For the recipient persona: can-act, ambiguous (finding required), would-push-back (finding required), already-known, not-mine. basis = the message-id of YOUR OWN mail, or a tree fact (file:line), that grounds the verdict - or the literal string \"no record\"; never a paraphrase of reputation. "
|
||||
"A no-comment on a unit that changes your file needs a message where you accepted the same construct; otherwise the basis is \"no record\".";
|
||||
|
||||
const std::string_view WholeFirst =
|
||||
"SCOPE - WHOLE PASS, and it gates the block passes of this lens: judge the artifact as an APPROACH - is this the right solution at all, architecturally and at the subsystem level (the alternatives, the maintainers' stated direction, what upstream already has)? "
|
||||
"Do not review individual hunks or sentences; per-block passes of this lens run only if you pass. Return `summary` (5-10 sentences: the approach as you judged it and the constraints the block passes must respect). Cover exactly the units listed below (the whole:* slots).";
|
||||
const std::string_view WholeAll =
|
||||
"SCOPE - WHOLE PASS of the consistency lens, and it gates the block passes: the artifact as a whole - the route it recommends and whether every dependent item carries it through (whole:route), the total set of asks and whether they are legible and free of contradictions (whole:asks), what a reader would expect and does not find (whole:absent), the ledger collision check of your charter, and contradictions between the parts of the artifact. "
|
||||
"Per-unit consistency is checked by parallel block passes of this lens that run only if you pass - do not duplicate them. Return `summary` (5-10 sentences the block passes rest on). Cover exactly the units listed below (the whole:* slots).";
|
||||
const std::string_view WholePersona =
|
||||
"SCOPE - WHOLE PASS as this person, and it gates the block passes: read the whole artifact as they would and write the review they would actually send (predictedReview), the disposition-review notes your charter requires, and cover exactly the units listed below (the whole:* slots). "
|
||||
"Return `summary` as a calibration digest for the block passes (this reviewer's pet issues, phrasing and imperatives, found in their own mail - name the message-ids). Return in `notMine` every unit id that is not this person's tree, file or decision - those units get no block pass from this persona; leave it empty for a recipient persona.";
|
||||
|
||||
const std::string_view HintAnchor =
|
||||
"This unit fixes the as-of date for every state statement in the artifact. Sweep lore for movement since that date in the threads the artifact cites (the prefetched references give the message-ids; use utilities/lore.py search for newer versions and replies) and report every statement the movement falsifies as a finding; a statement still true is part of your basis.";
|
||||
const std::string_view HintRefs =
|
||||
"Check that every [n] line resolves (the prefetched index), that the numbering is contiguous and matches the body, and that no entry is unused or orphaned; whether each citation is apt is judged by the unit that cites it.";
|
||||
const std::string_view HintOutsideKernel = "Judge the in-tree users and callers of what this patch changes, at the submission base, outside its own diff.";
|
||||
const std::string_view HintAbsentKernel = "Judge what a reviewer expects in this patch and does not find: a trailer, a test statement, a Cc, a binding property, an error path.";
|
||||
const std::string_view TextBlockHint = "Within this unit, verify its own dated statements against the anchor date and its own [n] citations against the prefetched raw files.";
|
||||
|
||||
const std::string_view WholeFirstRepo =
|
||||
"SCOPE - WHOLE PASS, and it gates the block passes of this lens: judge the range as an APPROACH for THIS repository - is this the right solution at all (an existing mechanism in the repository or its platform, the right layer or component, the right commit shape, compatibility with what users already have installed)? "
|
||||
"Do not review individual hunks; per-block passes of this lens run only if you pass. Return `summary` (5-10 sentences: the approach as you judged it and the constraints the block passes must respect). Cover exactly the units listed below (the whole:* slots).";
|
||||
|
|
@ -45,6 +72,19 @@ namespace Crafter::Review::Prompt {
|
|||
"Context lines are context and removed lines are not claims, except a context sentence this commit's own change makes false.";
|
||||
|
||||
std::string_view SlotDuty(std::string_view lensFile, std::string_view unitId) {
|
||||
if (lensFile == "etiquette.md" && unitId == "whole:asks") {
|
||||
return "; for this lens that includes Step 0 and the point map: every point the mail being answered raised - is each answered somewhere, none silently skipped? List them with where each is answered";
|
||||
}
|
||||
if (lensFile == "conciseness.md" && unitId == "whole:absent") {
|
||||
return "; for this lens that includes the growth calibration against the first reviewed version and cross-unit duplication (the same point made in two units)";
|
||||
}
|
||||
if (lensFile == "process-docs.md" && unitId == "whole:asks") return "; for this lens that includes recipients (get_maintainer), subject and cover mechanics";
|
||||
if (lensFile == "minimalism.md" && unitId == "whole:absent") {
|
||||
return "; for this lens that includes series-level minimalism: patches or hunks that are unnecessary as a whole, split or merged wrongly, or belong in another series";
|
||||
}
|
||||
if (lensFile == "facts.md" && unitId == "whole:route") {
|
||||
return "; for this lens that means the claims that span units - does every item that depends on the recommended route state the same facts about it";
|
||||
}
|
||||
if (lensFile != Plan::FactsLens) return {};
|
||||
if (unitId == "whole:order") {
|
||||
return "; for this lens that means each message describes its own commit alone - nothing a message claims is delivered by a later commit of the range, and no message describes the state a later commit creates";
|
||||
|
|
@ -82,16 +122,56 @@ namespace Crafter::Review::Prompt {
|
|||
}
|
||||
}
|
||||
|
||||
std::string SystemText() {
|
||||
std::string SystemText(std::string_view mode) {
|
||||
if (mode == "reply" || mode == "series") return Dyn::Replace(Dyn::ReadText(LensDir() / "_common.md"), "{{ARTIFACT_KIND}}", mode == "reply" ? "mailing-list reply" : "patch series");
|
||||
return Dyn::Replace(Dyn::ReadText(LensDir() / "_common-repo.md"), "{{ARTIFACT_KIND}}", "commit range");
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::string ArtifactLines(std::span<const std::string> lines) {
|
||||
std::vector<std::string> artifact;
|
||||
artifact.reserve(lines.size());
|
||||
for (std::size_t i = 0; i < lines.size(); ++i) artifact.push_back(std::format("{:04d}| {}", i + 1, lines[i]));
|
||||
return Dyn::Join(artifact, "\n");
|
||||
}
|
||||
|
||||
std::string InventoryLines(const Json& units) {
|
||||
std::vector<std::string> inventory;
|
||||
for (const Json& unit : units) {
|
||||
const Json& range = Dyn::At(unit, "lines");
|
||||
inventory.push_back(std::format("- {} [{}-{}] {}", Dyn::Str(Dyn::At(unit, "id")), Dyn::Str(range.at(0)), Dyn::Str(range.at(1)), Dyn::Str(Dyn::At(unit, "excerpt"))));
|
||||
}
|
||||
return Dyn::Join(inventory, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
std::string RunLayerKernel(std::string_view mode, std::string_view artifactRel, std::string_view subsystem, std::string_view base, std::span<const std::string> reviewers, std::string_view date,
|
||||
std::span<const std::string> trees, std::string_view hash, std::span<const std::string> lines, const Json& units, std::string_view refDigest,
|
||||
std::span<const std::string> contextPaths) {
|
||||
std::vector<std::string> inputs;
|
||||
inputs.push_back(std::format("- The frozen artifact (review THIS, at hash {}): {}", hash,
|
||||
mode == "reply" ? std::format("the reply draft file {} - inlined below; nothing else is an input", artifactRel)
|
||||
: std::format("the *.patch files in {} - inlined below in sorted order; nothing else in that dir is an input", artifactRel)));
|
||||
inputs.push_back(std::format("- Ledger: journal/{}/ledger.md (the only mutable journal file you may read)", subsystem));
|
||||
inputs.push_back(std::format("- Thread mboxes: journal/{}/captures/threads/", subsystem));
|
||||
inputs.push_back(std::format("- Evidence/proof artifacts: journal/{}/captures/ (index in the ledger)", subsystem));
|
||||
inputs.push_back(base.empty() ? std::string("- Target tree at the submission base: see the artifact") : std::format("- Target tree at the submission base: {}", base));
|
||||
if (!trees.empty()) inputs.push_back(std::format("- Trees: {}", Dyn::Join(trees, ", ")));
|
||||
if (!contextPaths.empty()) inputs.push_back(std::format("- Material the artifact discusses (read-only evidence; do not spend turns locating it): {}", Dyn::Join(contextPaths, ", ")));
|
||||
inputs.emplace_back("- History archaeology ONLY in work/milos-linux (work/linux is shallow; its history queries lie)");
|
||||
inputs.emplace_back("- lore.kernel.org ONLY via utilities/lore.py (an Anubis PoW wall blocks curl/WebFetch)");
|
||||
if (!reviewers.empty()) inputs.push_back(std::format("- Reviewers with a persona in this run: {}", Dyn::Join(reviewers, ", ")));
|
||||
inputs.push_back(std::format("- Run date: {}", date));
|
||||
return std::format("INPUTS:\n{}\n\nARTIFACT (frozen, hash {}), inlined with line numbers:\n{}\n\nINVENTORY - {} units, a MECHANICAL partition of the artifact (utilities/inventory.py: every non-blank line belongs to exactly one unit; fixed slots with lines 0-0 stand for what is NOT in the text):\n{}\n\n{}",
|
||||
Dyn::Join(inputs, "\n"), hash, ArtifactLines(lines), units.size(), InventoryLines(units), refDigest);
|
||||
}
|
||||
|
||||
std::string Charter(std::string_view lensFile) {
|
||||
return Dyn::ReadText(LensDir() / std::string(lensFile));
|
||||
}
|
||||
|
||||
std::string RunLayer(std::string_view artifactRel, std::string_view base, std::string_view date, std::span<const std::string> trees, std::string_view hash,
|
||||
std::span<const std::string> lines, const Json& units, std::span<const std::string> contextPaths, std::string_view repoName) {
|
||||
std::span<const std::string> lines, const Json& units, std::span<const std::string> contextPaths, std::string_view repoName, std::string_view subsystem) {
|
||||
std::vector<std::string> inputs;
|
||||
inputs.push_back(std::format("- The frozen artifact (review THIS, at hash {}): the *.patch files in {} - `git format-patch` of the commit range under review, inlined below in sorted order; nothing else in that dir is an input",
|
||||
hash, artifactRel));
|
||||
|
|
@ -99,6 +179,10 @@ namespace Crafter::Review::Prompt {
|
|||
repoName, Dyn::Join(trees, ", "), !trees.empty() && trees.front() == "." ? " (`.` is the working directory)" : ""));
|
||||
inputs.push_back(base.empty() ? std::string("- Range base: the base-commit line of the last patch")
|
||||
: std::format("- Range base (the state before the first commit; `git -C <tree> show <base>:<path>`): {}", base));
|
||||
if (!subsystem.empty()) {
|
||||
inputs.push_back(std::format("- Ledger: journal/{}/ledger.md (the only mutable journal file you may read)", subsystem));
|
||||
inputs.push_back(std::format("- Evidence/proof artifacts: journal/{}/captures/ (index in the ledger)", subsystem));
|
||||
}
|
||||
if (!contextPaths.empty()) {
|
||||
inputs.push_back(std::format("- Material the artifact discusses (read-only evidence; do not spend turns locating it): {}", Dyn::Join(contextPaths, ", ")));
|
||||
}
|
||||
|
|
@ -185,8 +269,13 @@ namespace Crafter::Review::Prompt {
|
|||
}
|
||||
|
||||
std::string LensLayer(std::string_view lensFile, std::string_view charterText, std::string_view dispositionsBlock, std::string_view app,
|
||||
std::string_view wholeSummary, std::string_view db) {
|
||||
std::vector<std::string> parts = {std::format("YOUR CHARTER (process/lenses/{}), verbatim:\n\n{}", lensFile, Dyn::Strip(charterText))};
|
||||
std::string_view wholeSummary, std::string_view db, std::string_view persona, std::string_view corpus) {
|
||||
std::vector<std::string> parts;
|
||||
if (!persona.empty()) {
|
||||
parts.push_back(std::format("Your persona: {}. You ARE this person, reviewing what they will actually read. Calibrate ONLY on mail they actually wrote (their replies to us and to recent similar series - fetch via utilities/lore.py).", persona));
|
||||
if (!corpus.empty()) parts.push_back(std::format("CALIBRATION MAP - a lore search listing of this person's recent mail (fetch the bodies you need):\n{}", Dyn::Slice(corpus, 0, 6000)));
|
||||
}
|
||||
parts.push_back(std::format("YOUR CHARTER (process/lenses/{}), verbatim:\n\n{}", lensFile, Dyn::Strip(charterText)));
|
||||
if (!app.empty()) parts.emplace_back(app);
|
||||
if (!db.empty()) parts.emplace_back(db);
|
||||
parts.emplace_back(dispositionsBlock);
|
||||
|
|
@ -199,15 +288,30 @@ namespace Crafter::Review::Prompt {
|
|||
std::string Tail(const Json& job, const Json& units, std::span<const std::string> lines, std::string_view wholeSummary) {
|
||||
const std::string lensFile = Dyn::At(job, "lensFile").get<std::string>();
|
||||
const Json& kind = Dyn::At(job, "kind");
|
||||
const Plan::Lens& lens = Plan::LensOf(lensFile);
|
||||
const std::string_view vocab = lensFile == Plan::PersonaLens ? PersonaVocab : lens.kernel ? GenericVocabKernel : GenericVocab;
|
||||
if (kind == "whole") {
|
||||
const std::string_view whole = Plan::LensOf(lensFile).whole;
|
||||
if (whole != "first-repo" && whole != "functional") throw Dyn::Error("KeyError", Dyn::ReprValue(whole.empty() ? Json() : Json(whole)));
|
||||
const std::string_view whole = lens.whole;
|
||||
std::string_view text;
|
||||
if (whole == "first-repo") {
|
||||
text = WholeFirstRepo;
|
||||
} else if (whole == "functional") {
|
||||
text = WholeFunctional;
|
||||
} else if (whole == "first") {
|
||||
text = WholeFirst;
|
||||
} else if (whole == "all") {
|
||||
text = WholeAll;
|
||||
} else if (whole == "persona") {
|
||||
text = WholePersona;
|
||||
} else {
|
||||
throw Dyn::Error("KeyError", Dyn::ReprValue(whole.empty() ? Json() : Json(whole)));
|
||||
}
|
||||
std::vector<std::string> listed;
|
||||
const Json& expected = Dyn::At(job, "expectedIds");
|
||||
for (const Json& unit : units) {
|
||||
if (Dyn::In(Dyn::At(unit, "id"), expected)) listed.push_back(std::format("- {} [0-0] {}", Dyn::Str(Dyn::At(unit, "id")), Dyn::Str(Dyn::At(unit, "excerpt"))));
|
||||
}
|
||||
return std::format("{}\n{}\nUnits to cover:\n{}", whole == "first-repo" ? WholeFirstRepo : WholeFunctional, GenericVocab, Dyn::Join(listed, "\n"));
|
||||
return std::format("{}\n{}\nUnits to cover:\n{}", text, vocab, Dyn::Join(listed, "\n"));
|
||||
}
|
||||
const Json* found = nullptr;
|
||||
for (const Json& unit : units) {
|
||||
|
|
@ -222,7 +326,7 @@ namespace Crafter::Review::Prompt {
|
|||
if (kind == "slot") {
|
||||
const std::string description = Dyn::Replace(Text(Dyn::At(u, "excerpt")), "FIXED SLOT: ", "");
|
||||
return std::format("SCOPE - SLOT PASS, unit \"{}\": this unit has no lines; it stands for a question about the whole artifact: {}. Answer it for your lens{}. Coverage: exactly this one unit.\n{}",
|
||||
id, description, SlotDuty(lensFile, id), GenericVocab);
|
||||
id, description, SlotDuty(lensFile, id), vocab);
|
||||
}
|
||||
const Json& range = Dyn::At(u, "lines");
|
||||
const std::int64_t a = IntItem(range, 0);
|
||||
|
|
@ -230,36 +334,44 @@ namespace Crafter::Review::Prompt {
|
|||
const Json& unitKind = Dyn::Get(job, "unitKind");
|
||||
const bool prose = unitKind == "text" || unitKind == "doc";
|
||||
std::string_view hint;
|
||||
if (id.ends_with(":outside")) {
|
||||
hint = HintOutside;
|
||||
if (id == "anchor") {
|
||||
hint = HintAnchor;
|
||||
} else if (id == "refs") {
|
||||
hint = HintRefs;
|
||||
} else if (id.ends_with(":outside")) {
|
||||
hint = lens.kernel ? HintOutsideKernel : HintOutside;
|
||||
} else if (id.ends_with(":absent")) {
|
||||
hint = HintAbsent;
|
||||
hint = lens.kernel ? HintAbsentKernel : HintAbsent;
|
||||
} else if (lensFile == Plan::FunctionalLens) {
|
||||
hint = FunctionalBlockHint;
|
||||
} else if (unitKind == "text") {
|
||||
hint = TextBlockHintRepo;
|
||||
hint = lens.kernel ? TextBlockHint : TextBlockHintRepo;
|
||||
} else if (unitKind == "doc") {
|
||||
hint = DocBlockHintRepo;
|
||||
}
|
||||
const std::string text = Plan::UnitText(lines, u);
|
||||
// The kernel modes' block judges a claim, a sentence or a hunk in one
|
||||
// phrase; the push gates' says which the unit is.
|
||||
const std::string_view against = lens.kernel ? "a claim at its source, a sentence against its proof obligation, a hunk against the standard"
|
||||
: prose ? "a claim at its source, a sentence against its proof obligation"
|
||||
: "a hunk against the standard";
|
||||
const std::string scope = std::format("SCOPE - BLOCK PASS, unit \"{}\" [lines {}-{}]: judge ONLY this unit, with your full attention by your charter - {} - reading the rest of the artifact only as context. Do not re-litigate the approach as a whole{}. Coverage: exactly this one unit.",
|
||||
id, a, b, prose ? "a claim at its source, a sentence against its proof obligation" : "a hunk against the standard",
|
||||
wholeSummary.empty() ? "" : " - the whole pass of this lens concluded as stated above");
|
||||
return std::format("{}{}\n\nUNIT TEXT (verbatim, lines {}-{}):\n{}\n\n{}", scope, hint.empty() ? std::string() : std::format("\n{}", hint), a, b, text, GenericVocab);
|
||||
id, a, b, against, wholeSummary.empty() ? "" : " - the whole pass of this lens concluded as stated above");
|
||||
return std::format("{}{}\n\nUNIT TEXT (verbatim, lines {}-{}):\n{}\n\n{}", scope, hint.empty() ? std::string() : std::format("\n{}", hint), a, b, text, vocab);
|
||||
}
|
||||
|
||||
std::string BudgetLine(const Json& job) {
|
||||
std::string BudgetLine(const Json& job, bool kernel) {
|
||||
return std::format("\n\nTool-call budget for this pass: {} (every tool call is one request; the pipeline stops the process at that count and a stopped pass "
|
||||
"returns NOTHING - the unit is then unaddressed and the lens NOT RETURNED). Batch independent reads into one call and return the structured output with margin to spare.",
|
||||
Dyn::Str(Dyn::Get(job, "maxTurns")));
|
||||
"returns NOTHING - the unit is then unaddressed and the lens NOT RETURNED). Batch independent reads into one call{} and return the structured output with margin to spare.",
|
||||
Dyn::Str(Dyn::Get(job, "maxTurns")), kernel ? ", read the prefetched raw files instead of fetching," : "");
|
||||
}
|
||||
|
||||
std::string SystemPrompt(std::string_view systemText, std::string_view run, std::string_view lens) {
|
||||
return std::format("{}{}{}{}{}", systemText, SepRun, run, SepLens, lens);
|
||||
}
|
||||
|
||||
std::string UserPrompt(std::string_view tail, const Json& job, std::string_view stack) {
|
||||
std::string UserPrompt(std::string_view tail, const Json& job, std::string_view stack, bool kernel) {
|
||||
return std::format("{}{}{}\n\nReturn the structured output described in your instructions.\n", tail, stack.empty() ? std::string() : std::format("\n\n{}", stack),
|
||||
Dyn::Truthy(job) ? BudgetLine(job) : std::string());
|
||||
Dyn::Truthy(job) ? BudgetLine(job, kernel) : std::string());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue