fix(run): the dry run's re-slice reads the line prefix to its bar
The re-slice self-check stripped six characters off every inlined artifact line - `0001| ` - and so failed from line 10000 on, where the number has five digits. The prefix is read to its bar now; a test freezes a 10,050-line file and dry-runs it.
This commit is contained in:
parent
d5e54ffeb3
commit
0e0983f278
2 changed files with 55 additions and 1 deletions
|
|
@ -2241,7 +2241,11 @@ namespace Crafter::Review::Run {
|
|||
const std::string after = runLayer.substr(at + marker.size());
|
||||
const std::string body = after.substr(0, after.find("\n\nINVENTORY - "));
|
||||
const std::vector<std::string> artLines = Dyn::Split(body, "\n");
|
||||
for (std::size_t i = 1; i < artLines.size(); ++i) art.push_back(Dyn::Slice(artLines[i], 6));
|
||||
// The line number prefix (`0001| `, five digits from line 10000 on - the self-review of 2026-11-01 found the fixed width).
|
||||
for (std::size_t i = 1; i < artLines.size(); ++i) {
|
||||
const std::size_t bar = artLines[i].find("| ");
|
||||
art.push_back(bar == std::string::npos ? artLines[i] : artLines[i].substr(bar + 2));
|
||||
}
|
||||
}
|
||||
for (const Json& u : units) {
|
||||
const Json& range = u.at("lines");
|
||||
|
|
|
|||
|
|
@ -525,6 +525,56 @@ echo "{\"type\":\"result\",\"subtype\":\"success\",\"is_error\":false,\"result\"
|
|||
Check("stop between gates: the next gate's pool starts aborted - none of its passes runs, and the abort is the run's",
|
||||
ran == 0 && g.abort && g.abort->starts_with("stopped by crafter-review stop") && res.size() == 1 && !res[0].at("coverageMissing").empty(), g.abort.value_or("None"));
|
||||
}
|
||||
// The dry run's re-slice reads the artifact back from the run layer
|
||||
// by stripping the line-number prefix - `0001| `, five digits from
|
||||
// line 10000 on. A fixed six characters was wrong there: the first
|
||||
// artifact past 9999 lines, the pipeline's own review of 2026-11-01,
|
||||
// refused itself at preflight.
|
||||
{
|
||||
const fs::path big = base / "big";
|
||||
fs::create_directories(big / ".review-gates");
|
||||
Write(big / ".review-gates" / "config.json", R"({"modes": {"commits": {"lenses": ["repo-bug-prover"]}}})");
|
||||
Git(big, {"init", "-q"});
|
||||
Git(big, {"config", "user.email", "me@example.com"});
|
||||
Git(big, {"config", "user.name", "Me"});
|
||||
Write(big / "README.md", "# big\n");
|
||||
Git(big, {"add", "."});
|
||||
Git(big, {"commit", "-q", "-m", "base"});
|
||||
const std::string bigBase = Dyn::Strip(Git(big, {"rev-parse", "HEAD"}).out);
|
||||
std::string wide;
|
||||
for (std::int32_t i = 0; i < 10'050; ++i) wide += std::format("line {}\n", i);
|
||||
Write(big / "wide.txt", wide);
|
||||
Git(big, {"add", "."});
|
||||
Git(big, {"commit", "-q", "-m", "add a wide file\n\nTen thousand and fifty lines."});
|
||||
const fs::path bigFake = base / "big-fake";
|
||||
Write(bigFake, "#!/bin/sh\nexit 1\n");
|
||||
fs::permissions(bigFake, fs::perms::owner_all);
|
||||
const fs::path bigOut = base / "big-out";
|
||||
const Process::Captured bigFreeze = Process::Run({Platform::SelfExe().string(), "freeze", "--out", bigOut.string(), "--base", bigBase}, big, std::chrono::seconds(60), {}, Env);
|
||||
Json bigRecord;
|
||||
try {
|
||||
bigRecord = Dyn::LoadJsonFile(bigOut / "freeze.json");
|
||||
} catch (const std::exception&) {
|
||||
}
|
||||
const std::string bigHash = bigRecord.is_object() ? Text(bigRecord.at("hash")) : std::string();
|
||||
std::string patchText;
|
||||
std::error_code bigError;
|
||||
for (fs::directory_iterator it(bigOut, bigError), end; !bigError && it != end; it.increment(bigError)) {
|
||||
if (it->path().extension() == ".patch") patchText = Platform::ReadFile(it->path()).value_or("");
|
||||
}
|
||||
const fs::path bigScratch = base / "big-scratch";
|
||||
const Process::Captured bigRun = Process::Run({Platform::SelfExe().string(), "run", "--artifact", bigOut.string(), "--hash", bigHash, "--base", bigBase, "--date", "2026-11-01", "--claude-bin",
|
||||
bigFake.string(), "--scratch", bigScratch.string(), "--seats", "local", "--no-probe", "--dry-run"},
|
||||
big, std::chrono::seconds(120), {}, Env);
|
||||
Json bigDry;
|
||||
try {
|
||||
bigDry = Dyn::LoadJsonFile(bigScratch / std::format("{}-run-1-dry", bigHash.substr(0, 8)) / "dry-run.json");
|
||||
} catch (const std::exception&) {
|
||||
}
|
||||
Check("an artifact past 9999 lines: the dry run's re-slice of the run layer's artifact matches every unit (the prefix is read to its bar, not six characters)",
|
||||
bigFreeze.returnCode == 0 && std::ranges::count(patchText, '\n') > 10'000 && bigRun.returnCode == 2 && bigDry.is_object() && Dyn::Truthy(bigDry.at("dryRun").at("resliceOk")),
|
||||
std::format("freeze {} run {}: {}{}", bigFreeze.returnCode, bigRun.returnCode, Dyn::Slice(bigRun.out, -600), bigRun.err));
|
||||
}
|
||||
fs::remove_all(base);
|
||||
return Failures ? 1 : 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue