From bee900e397d16301985f360c1c0044f5aa39e473 Mon Sep 17 00:00:00 2001 From: Taylor Gagne Date: Sat, 17 Oct 2026 00:22:21 -0700 Subject: [PATCH 01/10] bench(arb): declare the CGR-38 dev/held-out split and score either side Retrieval work for CGR-38 is developed on gin, caddy and clap only (the repos CGR-25 was tuned on) and reported on the 234 held-out samples from the other 22 repos. score.py --split dev|heldout filters before scoring, so BCY is packed on the same subset. Reproduces the held-out bin-v0.9.1 numbers (R@20 0.5164, MRR 0.2145, BCY@8k 0.3198; RepoMap 0.5402 / 0.1785 / 0.3363). Co-Authored-By: Claude Opus 5.5 --- bench/arb/score.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bench/arb/score.py b/bench/arb/score.py index fd93f36..d60a16f 100644 --- a/bench/arb/score.py +++ b/bench/arb/score.py @@ -23,6 +23,15 @@ POSITIVE_TASKS = ("code2test", "comment2context", "trace2code", "edit2ripple") RANK_KEYS = ("Recall@5", "Recall@10", "Recall@20", "MRR") BUDGETS = (4_000, 8_000, 16_000, 32_000) +# Declared 2026-10-17 (CGR-38), before any retrieval change was tuned against it. Retrieval +# work is developed and diagnosed on the dev repos only (they hold the 40 samples CGR-25 was +# tuned on) and reported on the held-out remainder. Changing this set invalidates held-out numbers. +DEV_REPOS = frozenset({"gin-gonic/gin", "caddyserver/caddy", "clap-rs/clap"}) +SPLITS = { + "all": lambda repo: True, + "dev": lambda repo: repo in DEV_REPOS, + "heldout": lambda repo: repo not in DEV_REPOS, +} def read_jsonl(path: Path) -> list[dict[str, Any]]: @@ -163,6 +172,7 @@ def main(argv: list[str] | None = None) -> int: parser.add_argument("--data", type=Path, required=True) parser.add_argument("--out", type=Path, required=True) parser.add_argument("--markdown", type=Path, help="Also write the tables as Markdown.") + parser.add_argument("--split", choices=sorted(SPLITS), default="all", help="Score only the dev or held-out repos (DEV_REPOS).") parser.add_argument("methods", nargs="+", help="LABEL=DIR (CGraph layout) or LABEL=DIR:suffix (ARB baseline layout)") args = parser.parse_args(argv) sys.path.insert(0, str(args.arb_src / "src")) @@ -186,6 +196,7 @@ def main(argv: list[str] | None = None) -> int: details.extend(read_jsonl(path)) elif task != "abstention": parser.error(f"{path} missing") + details = [d for d in details if SPLITS[args.split](d["repo"])] entry = { "metrics": score_method(details, cache, bcy_curve), "given_excluded": score_given_excluded(details, samples, cache, bcy_curve), From e79ec101f69209d948e62577df98f9836ff649ea Mon Sep 17 00:00:00 2001 From: Taylor Gagne Date: Sat, 17 Oct 2026 00:44:03 -0700 Subject: [PATCH 02/10] feat(graph): tests edges from a test file to the source file it names Calls from a test reach the code under test only when call resolution is unambiguous, so most test files were islands: context and impact from a source file never reached its tests. A build pass (one-shot and incremental) now adds an inferred `tests` edge from each test file to the source file its name pairs with, reusing is_test_source_path and co_change's stem pairing (moved next to it). A stem several source files share pairs only by same directory, the mirrored directory under a test root, or a unique match; otherwise no edge. common_source_root() replaces the inline root derivation in contracts.cpp. Index version key -> logic-26 (graph shape changed). ARB dev split (gin/caddy/clap, 111): R@20 0.8859 -> 0.8994, MRR 0.4199 -> 0.4721, BCY@8k 0.6682 -> 0.6907 vs bin-v0.9.5. Held-out not scored. bench: cgraph_eval.py --split, and per-task details files always exist. Co-Authored-By: Claude Opus 5.5 --- bench/arb/cgraph_eval.py | 6 +- src/engine/co_change.cpp | 24 +--- src/engine/contracts.cpp | 16 +-- src/engine/data_contracts.cpp | 16 +++ src/engine/graph_builder.cpp | 129 +++++++++++++++++++ src/engine/include/cgraph/data_contracts.hpp | 7 + src/engine/include/cgraph/graph_builder.hpp | 14 ++ src/engine/incremental_update.cpp | 1 + src/engine/index_persistence.cpp | 2 +- src/engine/pipeline.cpp | 1 + tests/smoke/graph_builder_test.cpp | 55 ++++++++ 11 files changed, 231 insertions(+), 40 deletions(-) diff --git a/bench/arb/cgraph_eval.py b/bench/arb/cgraph_eval.py index 9aa30c1..f7ed97a 100644 --- a/bench/arb/cgraph_eval.py +++ b/bench/arb/cgraph_eval.py @@ -48,6 +48,7 @@ from typing import Any, Iterator import snapshots +from score import SPLITS RRF_K = 60 CONTEXT_BUDGET = 8000 @@ -442,6 +443,8 @@ def main(argv: list[str] | None = None) -> int: parser.add_argument("--jobs", type=int, default=4) parser.add_argument("--limit", type=int, default=0, help="Evaluate at most N samples per task (0 = all).") parser.add_argument("--keep-snapshots", action="store_true") + parser.add_argument("--split", choices=sorted(SPLITS), default="all", + help="Evaluate only the dev or held-out repos (score.DEV_REPOS).") args = parser.parse_args(argv) if args.cgraph_bin_dir is None: parser.error("no cgraph on PATH; pass --cgraph-bin-dir") @@ -460,6 +463,7 @@ def main(argv: list[str] | None = None) -> int: skipped: dict[str, dict[str, int]] = defaultdict(lambda: defaultdict(int)) for task in args.tasks: details_path = args.out / f"{task}_details.jsonl" + details_path.touch() # a split can hold no sample of a task; score.py still expects the file done[task] = set() if details_path.exists(): done[task] = {json.loads(l)["sample_id"] for l in details_path.read_text().splitlines() if l.strip()} @@ -468,7 +472,7 @@ def main(argv: list[str] | None = None) -> int: if args.limit: samples = samples[: args.limit] for sample in samples: - if sample["id"] in done[task]: + if sample["id"] in done[task] or not SPLITS[args.split](sample["repo"]): continue if task != "abstention" and baseline.query_has_leakage(sample, baseline.query_text_for_eval(sample)): skipped[task]["query_leakage"] += 1 diff --git a/src/engine/co_change.cpp b/src/engine/co_change.cpp index b260037..c4a72be 100644 --- a/src/engine/co_change.cpp +++ b/src/engine/co_change.cpp @@ -1,4 +1,5 @@ #include "cgraph/co_change.hpp" +#include "cgraph/data_contracts.hpp" #include #include @@ -36,29 +37,6 @@ struct Candidate { return slash == std::string_view::npos ? std::string_view{} : path.substr(0, slash); } -[[nodiscard]] std::string_view basename_of(std::string_view path) { - const auto slash = path.rfind('/'); - return slash == std::string_view::npos ? path : path.substr(slash + 1); -} - -// The file name without its last extension: `a.test.ts` -> `a.test`. -[[nodiscard]] std::string_view stem_of(std::string_view path) { - const auto base = basename_of(path); - const auto dot = base.rfind('.'); - return dot == std::string_view::npos || dot == 0 ? base : base.substr(0, dot); -} - -// The stem with one test marker removed (`test_x`, `x_test`, `x_tests`, -// `x.test`, `x.spec`, `x_spec`, `XTest`, `XTests`), or the stem itself. -[[nodiscard]] std::string_view test_core(std::string_view stem) { - if (stem.starts_with("test_") && stem.size() > 5) return stem.substr(5); - static constexpr std::array kSuffixes{"_tests", "_test", ".test", ".spec", "_spec", "Tests", "Test"}; - for (const auto suffix : kSuffixes) { - if (stem.ends_with(suffix) && stem.size() > suffix.size()) return stem.substr(0, stem.size() - suffix.size()); - } - return stem; -} - [[nodiscard]] std::string ticked(std::string_view label) { return "`" + std::string(label) + "`"; } diff --git a/src/engine/contracts.cpp b/src/engine/contracts.cpp index 8b0ed37..36dd940 100644 --- a/src/engine/contracts.cpp +++ b/src/engine/contracts.cpp @@ -940,21 +940,7 @@ void resolve_contracts(GraphSnapshot& graph, std::span raw_re // otherwise unused reader exercises it, no request reaches it. // Paths read relative to the directory every file node shares, the // project root (node source files are absolute). - std::string project_root; - bool first_file = true; - for (const auto& node : graph.nodes) { - if (node.kind != "file" || node.source_file.empty()) { - continue; - } - if (first_file) { - project_root = node.source_file; - first_file = false; - } else { - const auto mismatch = std::ranges::mismatch(project_root, node.source_file); - project_root.resize(static_cast(mismatch.in1 - project_root.begin())); - } - } - project_root.resize(project_root.rfind('/') == std::string::npos ? 0 : project_root.rfind('/') + 1); + const auto project_root = common_source_root(graph); const auto from_test = [&](const std::string& id) { const auto source = by_id.find(id); if (source == by_id.end() || !source->second->source_file.starts_with(project_root)) { diff --git a/src/engine/data_contracts.cpp b/src/engine/data_contracts.cpp index bd6e174..131b48c 100644 --- a/src/engine/data_contracts.cpp +++ b/src/engine/data_contracts.cpp @@ -1093,6 +1093,22 @@ std::vector cypher_text_labels(std::string_view text, bool require_ return out; } +std::string_view stem_of(std::string_view path) { + const auto slash = path.rfind('/'); + const auto base = slash == std::string_view::npos ? path : path.substr(slash + 1); + const auto dot = base.rfind('.'); + return dot == std::string_view::npos || dot == 0 ? base : base.substr(0, dot); +} + +std::string_view test_core(std::string_view stem) { + if (stem.starts_with("test_") && stem.size() > 5) return stem.substr(5); + static constexpr std::array kSuffixes{"_tests", "_test", ".test", ".spec", "_spec", "Tests", "Test"}; + for (const auto suffix : kSuffixes) { + if (stem.ends_with(suffix) && stem.size() > suffix.size()) return stem.substr(0, stem.size() - suffix.size()); + } + return stem; +} + bool is_test_source_path(std::string_view relative_path) { const std::filesystem::path path{std::string(relative_path)}; for (const auto& part : path.parent_path()) { diff --git a/src/engine/graph_builder.cpp b/src/engine/graph_builder.cpp index 45a878d..5eb3ba6 100644 --- a/src/engine/graph_builder.cpp +++ b/src/engine/graph_builder.cpp @@ -1,6 +1,7 @@ #include "cgraph/graph_builder.hpp" #include "cgraph/claim_contracts.hpp" +#include "cgraph/data_contracts.hpp" #include "cgraph/detect.hpp" #include "cgraph/normalize.hpp" @@ -1700,6 +1701,134 @@ void resolve_raw_relations(GraphSnapshot& graph, std::span ra } + +std::string common_source_root(const GraphSnapshot& graph) { + std::string root; + bool first_file = true; + for (const auto& node : graph.nodes) { + if (node.kind != "file" || node.source_file.empty()) { + continue; + } + if (first_file) { + root = node.source_file; + first_file = false; + } else { + const auto mismatch = std::ranges::mismatch(root, node.source_file); + root.resize(static_cast(mismatch.in1 - root.begin())); + } + } + root.resize(root.rfind('/') == std::string::npos ? 0 : root.rfind('/') + 1); + return root; +} + +void resolve_test_subjects(GraphSnapshot& graph) { + const auto root = common_source_root(graph); + const auto directory_of = [](std::string_view path) { + const auto slash = path.rfind('/'); + return slash == std::string_view::npos ? std::string_view{} : path.substr(0, slash); + }; + // Test markers in the name, so a Rust `foo_test.rs` or a `button.spec.ts` + // outside a test directory still counts; Java's `XTest` is left to + // is_test_source_path, which guards it against `ABTest`. + const auto named_as_test = [](std::string_view stem) { + return stem.starts_with("test_") || stem.ends_with("_test") || stem.ends_with("_tests") || + stem.ends_with(".test") || stem.ends_with(".spec") || stem.ends_with("_spec"); + }; + // `tests/http/client_test.py` mirrors `http/`: the directory with every test + // root segment removed. + const auto mirrored_directory = [](std::string_view dir) { + std::string out; + std::size_t start = 0; + while (start <= dir.size()) { + const auto end = std::min(dir.find('/', start), dir.size()); + const auto segment = dir.substr(start, end - start); + if (!segment.empty() && segment != "test" && segment != "tests" && segment != "__tests__" && + segment != "spec" && segment != "specs" && segment != "e2e" && segment != "integrationTest") { + if (!out.empty()) out += '/'; + out += segment; + } + start = end + 1; + } + return out; + }; + + struct File { + const Node* node; + std::string_view relative; + }; + std::vector tests; + std::unordered_map> sources_by_stem; + for (const auto& node : graph.nodes) { + if (node.kind != "file" || node.source_file.empty() || !node.source_file.starts_with(root)) { + continue; + } + const File file{&node, std::string_view(node.source_file).substr(root.size())}; + const auto stem = stem_of(file.relative); + if (is_test_source_path(file.relative) || named_as_test(stem)) { + tests.push_back(file); + } else { + sources_by_stem[stem].push_back(file); + } + } + if (tests.empty()) { + return; + } + + std::unordered_set seen_edges; + seen_edges.reserve(graph.edges.size()); + for (const auto& edge : graph.edges) { + seen_edges.insert(edge_key(edge)); + } + std::vector added; + const auto link = [&](const File& test, const File& subject) { + Edge edge{.source = test.node->id, .target = subject.node->id, .relation = "tests", + .confidence = Confidence::Inferred}; + if (seen_edges.insert(edge_key(edge)).second) { + added.push_back(std::move(edge)); + } + }; + for (const auto& test : tests) { + const auto found = sources_by_stem.find(test_core(stem_of(test.relative))); + if (found == sources_by_stem.end()) { + continue; + } + const auto& candidates = found->second; + const auto dir = directory_of(test.relative); + bool linked = false; + for (const auto& candidate : candidates) { + if (directory_of(candidate.relative) == dir) { + link(test, candidate); + linked = true; + } + } + if (linked) { + continue; + } + if (candidates.size() == 1) { + link(test, candidates.front()); + continue; + } + const auto mirror = mirrored_directory(dir); + if (mirror.empty()) { + continue; + } + const File* only = nullptr; + std::size_t matches = 0; + for (const auto& candidate : candidates) { + const auto candidate_dir = directory_of(candidate.relative); + if (candidate_dir == mirror || + (candidate_dir.ends_with(mirror) && candidate_dir[candidate_dir.size() - mirror.size() - 1] == '/')) { + only = &candidate; + ++matches; + } + } + if (matches == 1) { + link(test, *only); + } + } + graph.edges.insert(graph.edges.end(), std::make_move_iterator(added.begin()), std::make_move_iterator(added.end())); +} + void resolve_interface_dispatch(GraphSnapshot& graph, std::span raw_calls) { // Interface method nodes, grouped by their owning interface (the `method` // edge the extractor emitted alongside the tagged node). diff --git a/src/engine/include/cgraph/data_contracts.hpp b/src/engine/include/cgraph/data_contracts.hpp index 5221137..65760ff 100644 --- a/src/engine/include/cgraph/data_contracts.hpp +++ b/src/engine/include/cgraph/data_contracts.hpp @@ -84,6 +84,13 @@ namespace cgraph { // Whether a repo-relative path is a test file (above). [[nodiscard]] bool is_test_source_path(std::string_view relative_path); +// The file name without its last extension: `a.test.ts` -> `a.test`. +[[nodiscard]] std::string_view stem_of(std::string_view path); + +// The stem with one test marker removed (`test_x`, `x_test`, `x_tests`, +// `x.test`, `x.spec`, `x_spec`, `XTest`, `XTests`), or the stem itself. +[[nodiscard]] std::string_view test_core(std::string_view stem); + // Facts for one parsed source file of a tree-sitter language: SQL and Cypher // string literals for every language named above, Spring Data Neo4j // annotations for Kotlin and Java, Drizzle query-builder table arguments diff --git a/src/engine/include/cgraph/graph_builder.hpp b/src/engine/include/cgraph/graph_builder.hpp index 436e463..b683761 100644 --- a/src/engine/include/cgraph/graph_builder.hpp +++ b/src/engine/include/cgraph/graph_builder.hpp @@ -74,6 +74,20 @@ void resolve_raw_calls(GraphSnapshot& graph, std::span raw_calls, // alone cannot bind. Runs after resolve_raw_relations (needs `method_of`). void resolve_interface_dispatch(GraphSnapshot& graph, std::span raw_calls); +// The directory every file node's (absolute) source file shares, with a +// trailing slash: the project root, so `source_file.substr(root.size())` is +// repo-relative. Empty when no file node has a source file. +[[nodiscard]] std::string common_source_root(const GraphSnapshot& graph); + +// Test-to-subject edges: `tests` from a test file node to the source file node +// its name pairs with (`path_test.go` -> `path.go`, `test_core.py` -> `core.py`, +// `button.spec.ts` -> `button.ts`, `tests/help.rs` -> `src/help.rs`). Calls +// from a test reach its subject only when call resolution is unambiguous, so +// without this most tests are islands. A stem several source files share pairs +// only within the test's own directory, the directory its test-root-free path +// mirrors, or a unique match; otherwise no edge. +void resolve_test_subjects(GraphSnapshot& graph); + void resolve_raw_relations(GraphSnapshot& graph, std::span raw_relations); } // namespace cgraph diff --git a/src/engine/incremental_update.cpp b/src/engine/incremental_update.cpp index 61b21a0..a59aedf 100644 --- a/src/engine/incremental_update.cpp +++ b/src/engine/incremental_update.cpp @@ -78,6 +78,7 @@ namespace { resolve_raw_relations(graph, raw_relations); resolve_contracts(graph, raw_relations, &contracts); resolve_interface_dispatch(graph, raw_calls); + resolve_test_subjects(graph); return graph; } diff --git a/src/engine/index_persistence.cpp b/src/engine/index_persistence.cpp index e7f7013..3831622 100644 --- a/src/engine/index_persistence.cpp +++ b/src/engine/index_persistence.cpp @@ -28,7 +28,7 @@ namespace { // golden/parity tests catch an *unintended* output change; bumping this key on an // *intended* one is an author/reviewer responsibility, like any on-disk schema // version. -constexpr const char* kIndexVersionKey = "cgraph-index-v1:logic-25"; +constexpr const char* kIndexVersionKey = "cgraph-index-v1:logic-26"; [[nodiscard]] std::string normalized_key(const std::filesystem::path& path) { return path.lexically_normal().generic_string(); diff --git a/src/engine/pipeline.cpp b/src/engine/pipeline.cpp index 7a70f16..ec1844c 100644 --- a/src/engine/pipeline.cpp +++ b/src/engine/pipeline.cpp @@ -96,6 +96,7 @@ PipelineResult run_one_shot(const std::filesystem::path& root) { resolve_raw_relations(result.graph, raw_relations); resolve_contracts(result.graph, raw_relations, &result.stats.contracts); resolve_interface_dispatch(result.graph, raw_calls); + resolve_test_subjects(result.graph); } { ScopedTimer timer(&result.stats.dedup_ms); diff --git a/tests/smoke/graph_builder_test.cpp b/tests/smoke/graph_builder_test.cpp index 7c37683..e20b3fa 100644 --- a/tests/smoke/graph_builder_test.cpp +++ b/tests/smoke/graph_builder_test.cpp @@ -1012,7 +1012,62 @@ int check_shared_stub_alias_binds_both_names() { } // namespace +// resolve_test_subjects pairs each test file with the source file its name +// names, using repo-relative paths (the project root here sits under a `tests` +// directory, which must not make every file a test). A stem several source files +// share pairs only by same directory or mirrored directory, never by guess. +int test_resolve_test_subjects() { + const std::string root = "/work/tests/proj/"; + cgraph::GraphSnapshot graph; + const auto file = [&](const std::string& relative) { + const auto id = cgraph::make_id(root + relative); + graph.nodes.push_back({.id = id, .label = relative, .source_file = root + relative, .kind = "file"}); + return id; + }; + const auto path_go = file("path.go"); + const auto path_test_go = file("path_test.go"); + const auto http_client = file("http/client.py"); + const auto db_client = file("db/client.py"); + const auto test_http_client = file("tests/http/test_client.py"); + const auto test_other_client = file("tests/test_client.py"); + const auto help_rs = file("src/output/help.rs"); + const auto tests_help_rs = file("tests/builder/help.rs"); + const auto button = file("ui/button.ts"); + const auto button_spec = file("ui/button.spec.ts"); + const auto lib_mod = file("src/a/mod.rs"); + const auto other_mod = file("src/b/mod.rs"); + const auto tests_mod = file("tests/mod.rs"); + const auto lonely_test = file("orphan_test.go"); + const auto plain = file("server.go"); + + cgraph::resolve_test_subjects(graph); + + const auto tests_edges = std::ranges::count_if(graph.edges, [](const cgraph::Edge& e) { return e.relation == "tests"; }); + if (!has_edge(graph, path_test_go, path_go, "tests")) return 1; // same directory + if (!has_edge(graph, test_http_client, http_client, "tests")) return 1; // mirrored tests/http -> http + if (has_edge(graph, test_http_client, db_client, "tests")) return 1; + if (!has_edge(graph, tests_help_rs, help_rs, "tests")) return 1; // unique stem anywhere + if (!has_edge(graph, button_spec, button, "tests")) return 1; // `.spec` marker + // tests/test_client.py mirrors the root, where no client.py lives: ambiguous, no edge. + if (has_edge(graph, test_other_client, http_client, "tests") || has_edge(graph, test_other_client, db_client, "tests")) return 1; + if (has_edge(graph, tests_mod, lib_mod, "tests") || has_edge(graph, tests_mod, other_mod, "tests")) return 1; + (void)lonely_test; + (void)plain; + if (tests_edges != 4) { + std::fprintf(stderr, "expected 4 tests edges, got %td\n", tests_edges); + return 1; + } + // Idempotent: a second pass (incremental rebuild) adds nothing. + cgraph::resolve_test_subjects(graph); + if (std::ranges::count_if(graph.edges, [](const cgraph::Edge& e) { return e.relation == "tests"; }) != tests_edges) return 1; + return 0; +} + int main() { + if (test_resolve_test_subjects() != 0) { + std::fprintf(stderr, "FAIL test_resolve_test_subjects\n"); + return 1; + } if (test_contract_facts_are_not_edges() != 0) { std::fprintf(stderr, "FAIL test_contract_facts_are_not_edges\n"); return 1; From 25933c27deec9ca117652ec95306bce51a8978b8 Mon Sep 17 00:00:00 2001 From: Taylor Gagne Date: Sat, 17 Oct 2026 00:48:17 -0700 Subject: [PATCH 03/10] fix(graph): scope cross-directory test pairing to the test's package On clap the unique-stem fallback paired five tests/testsuite/main.rs files with examples/typed-derive/main.rs, tests/builder/utils.rs with clap_complete's utils.rs and a nushell test with an example. Beyond its own directory a test now pairs only inside its package (what precedes its test root), generic names (main, mod, lib, index, utils...) pair only in-directory, and example, doc and bench files are never subjects. clap 21 -> 13 tests edges (all correct by inspection), gin unchanged at 27; ARB dev split unchanged. Co-Authored-By: Claude Opus 5.5 --- src/engine/graph_builder.cpp | 75 ++++++++++++++++----- src/engine/include/cgraph/graph_builder.hpp | 8 ++- tests/smoke/graph_builder_test.cpp | 16 ++++- tests/smoke/index_persistence_test.cpp | 2 +- 4 files changed, 77 insertions(+), 24 deletions(-) diff --git a/src/engine/graph_builder.cpp b/src/engine/graph_builder.cpp index 5eb3ba6..0452997 100644 --- a/src/engine/graph_builder.cpp +++ b/src/engine/graph_builder.cpp @@ -1734,23 +1734,57 @@ void resolve_test_subjects(GraphSnapshot& graph) { return stem.starts_with("test_") || stem.ends_with("_test") || stem.ends_with("_tests") || stem.ends_with(".test") || stem.ends_with(".spec") || stem.ends_with("_spec"); }; + const auto test_root_segment = [](std::string_view segment) { + return segment == "test" || segment == "tests" || segment == "__tests__" || segment == "spec" || + segment == "specs" || segment == "e2e" || segment == "integrationTest"; + }; // `tests/http/client_test.py` mirrors `http/`: the directory with every test - // root segment removed. - const auto mirrored_directory = [](std::string_view dir) { - std::string out; + // root segment removed. `package` is what precedes the first test root + // (`clap_complete/` for `clap_complete/tests/x.rs`): a package's tests test it. + struct TestLocation { + std::string mirror; + std::string_view package; + }; + const auto locate = [&](std::string_view dir) { + TestLocation out; + bool in_test_root = false; std::size_t start = 0; while (start <= dir.size()) { const auto end = std::min(dir.find('/', start), dir.size()); const auto segment = dir.substr(start, end - start); - if (!segment.empty() && segment != "test" && segment != "tests" && segment != "__tests__" && - segment != "spec" && segment != "specs" && segment != "e2e" && segment != "integrationTest") { - if (!out.empty()) out += '/'; - out += segment; + if (test_root_segment(segment)) { + if (!in_test_root) out.package = dir.substr(0, start); + in_test_root = true; + } else if (!segment.empty()) { + if (!out.mirror.empty()) out.mirror += '/'; + out.mirror += segment; } start = end + 1; } return out; }; + // Entry points and helper modules share their name across packages by + // convention, so a test named for one pairs only within its own directory. + const auto generic_stem = [](std::string_view stem) { + return stem == "main" || stem == "mod" || stem == "lib" || stem == "index" || stem == "__init__" || + stem == "utils" || stem == "util" || stem == "helpers" || stem == "common" || stem == "conftest" || + stem == "setup"; + }; + // Examples, docs and benchmarks use the library; they are not what a test covers. + const auto non_subject = [](std::string_view relative) { + std::size_t start = 0; + while (start < relative.size()) { + const auto end = relative.find('/', start); + if (end == std::string_view::npos) break; + const auto segment = relative.substr(start, end - start); + if (segment == "examples" || segment == "example" || segment == "docs" || segment == "doc" || + segment == "benches" || segment == "bench" || segment == "benchmarks") { + return true; + } + start = end + 1; + } + return false; + }; struct File { const Node* node; @@ -1766,7 +1800,7 @@ void resolve_test_subjects(GraphSnapshot& graph) { const auto stem = stem_of(file.relative); if (is_test_source_path(file.relative) || named_as_test(stem)) { tests.push_back(file); - } else { + } else if (!non_subject(file.relative)) { sources_by_stem[stem].push_back(file); } } @@ -1788,37 +1822,42 @@ void resolve_test_subjects(GraphSnapshot& graph) { } }; for (const auto& test : tests) { - const auto found = sources_by_stem.find(test_core(stem_of(test.relative))); + const auto core = test_core(stem_of(test.relative)); + const auto found = sources_by_stem.find(core); if (found == sources_by_stem.end()) { continue; } - const auto& candidates = found->second; const auto dir = directory_of(test.relative); bool linked = false; - for (const auto& candidate : candidates) { + for (const auto& candidate : found->second) { if (directory_of(candidate.relative) == dir) { link(test, candidate); linked = true; } } - if (linked) { + if (linked || generic_stem(core)) { continue; } + const auto location = locate(dir); + std::vector candidates; + for (const auto& candidate : found->second) { + if (candidate.relative.starts_with(location.package)) candidates.push_back(&candidate); + } if (candidates.size() == 1) { - link(test, candidates.front()); + link(test, *candidates.front()); continue; } - const auto mirror = mirrored_directory(dir); - if (mirror.empty()) { + if (location.mirror.empty()) { continue; } const File* only = nullptr; std::size_t matches = 0; - for (const auto& candidate : candidates) { - const auto candidate_dir = directory_of(candidate.relative); + for (const auto* candidate : candidates) { + const auto candidate_dir = directory_of(candidate->relative); + const auto& mirror = location.mirror; if (candidate_dir == mirror || (candidate_dir.ends_with(mirror) && candidate_dir[candidate_dir.size() - mirror.size() - 1] == '/')) { - only = &candidate; + only = candidate; ++matches; } } diff --git a/src/engine/include/cgraph/graph_builder.hpp b/src/engine/include/cgraph/graph_builder.hpp index b683761..bac0d4d 100644 --- a/src/engine/include/cgraph/graph_builder.hpp +++ b/src/engine/include/cgraph/graph_builder.hpp @@ -83,9 +83,11 @@ void resolve_interface_dispatch(GraphSnapshot& graph, std::span r // its name pairs with (`path_test.go` -> `path.go`, `test_core.py` -> `core.py`, // `button.spec.ts` -> `button.ts`, `tests/help.rs` -> `src/help.rs`). Calls // from a test reach its subject only when call resolution is unambiguous, so -// without this most tests are islands. A stem several source files share pairs -// only within the test's own directory, the directory its test-root-free path -// mirrors, or a unique match; otherwise no edge. +// without this most tests are islands. Beyond the test's own directory a pair +// must be the unique match inside the test's package (what precedes its test +// root) or the one file in the directory its test-root-free path mirrors. +// Generic names (`main`, `mod`, `index`, `utils`...) pair only in-directory, +// and example/doc/bench files are never subjects. void resolve_test_subjects(GraphSnapshot& graph); void resolve_raw_relations(GraphSnapshot& graph, std::span raw_relations); diff --git a/tests/smoke/graph_builder_test.cpp b/tests/smoke/graph_builder_test.cpp index e20b3fa..4beb9e3 100644 --- a/tests/smoke/graph_builder_test.cpp +++ b/tests/smoke/graph_builder_test.cpp @@ -1038,6 +1038,15 @@ int test_resolve_test_subjects() { const auto other_mod = file("src/b/mod.rs"); const auto tests_mod = file("tests/mod.rs"); const auto lonely_test = file("orphan_test.go"); + // A package's tests pair inside that package, even when the stem is unique to neither. + const auto widget_a = file("pkg_a/src/widget.rs"); + const auto widget_b = file("pkg_b/src/widget.rs"); + const auto widget_test = file("pkg_a/tests/widget.rs"); + // Generic names and example files never pair across directories. + const auto suite_main = file("crate/tests/testsuite/main.rs"); + const auto example_main = file("examples/demo/main.rs"); + const auto completion_test = file("other/tests/completion.rs"); + const auto example_completion = file("lib/examples/completion.rs"); const auto plain = file("server.go"); cgraph::resolve_test_subjects(graph); @@ -1051,10 +1060,13 @@ int test_resolve_test_subjects() { // tests/test_client.py mirrors the root, where no client.py lives: ambiguous, no edge. if (has_edge(graph, test_other_client, http_client, "tests") || has_edge(graph, test_other_client, db_client, "tests")) return 1; if (has_edge(graph, tests_mod, lib_mod, "tests") || has_edge(graph, tests_mod, other_mod, "tests")) return 1; + if (!has_edge(graph, widget_test, widget_a, "tests") || has_edge(graph, widget_test, widget_b, "tests")) return 1; + if (has_edge(graph, suite_main, example_main, "tests")) return 1; + if (has_edge(graph, completion_test, example_completion, "tests")) return 1; (void)lonely_test; (void)plain; - if (tests_edges != 4) { - std::fprintf(stderr, "expected 4 tests edges, got %td\n", tests_edges); + if (tests_edges != 5) { + std::fprintf(stderr, "expected 5 tests edges, got %td\n", tests_edges); return 1; } // Idempotent: a second pass (incremental rebuild) adds nothing. diff --git a/tests/smoke/index_persistence_test.cpp b/tests/smoke/index_persistence_test.cpp index 9bdc575..7d34332 100644 --- a/tests/smoke/index_persistence_test.cpp +++ b/tests/smoke/index_persistence_test.cpp @@ -44,7 +44,7 @@ int main() { // rebuild or re-sign, forcing a cold rebuild on the next query. The trailing // segment must therefore stay a short literal (bumped by hand on parity-surface // changes) and never a 64-char hex digest. Update this literal when you bump it. - if (key != "cgraph-index-v1:logic-25") { + if (key != "cgraph-index-v1:logic-26") { fs::remove_all(root); return 1; } From 968b654127bfbf4d1eb134c9fa4d05061404b32c Mon Sep 17 00:00:00 2001 From: Taylor Gagne Date: Sat, 17 Oct 2026 02:30:55 -0700 Subject: [PATCH 04/10] feat(search): a file's body document holds its unenclosed text and path A file node's span is its first line, so text no symbol encloses (top-level statements, a test file's anonymous test(...) blocks, data modules) was in no BM25 document, and neither was the file's path. The file node's document is now the lines no other node's span covers, plus its path terms; symbol documents are unchanged and nothing is counted twice. External dev set (CGR-38; 10 repos outside ARB, code2test + edit2ripple): code2test R@20 0.7031 -> 0.7460, BCY@8k 0.5138 -> 0.5573 over the tests-edge build. ARB dev split R@20 0.8994 -> 0.8979, MRR 0.4721 -> 0.4774. Co-Authored-By: Claude Opus 5.5 --- src/engine/body_index.cpp | 43 ++++++++++++++++++++++++++++----- tests/smoke/body_index_test.cpp | 27 +++++++++++++++++++++ 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/src/engine/body_index.cpp b/src/engine/body_index.cpp index 54fe700..ad349d6 100644 --- a/src/engine/body_index.cpp +++ b/src/engine/body_index.cpp @@ -179,8 +179,35 @@ void mix(std::uint64_t& hash, std::uint32_t value) { const auto line_count = static_cast(line_first_token.size()); line_first_token.push_back(stream.size()); - std::vector counts(file.terms.size(), 0); + // A file node's own span is its first line, so text no symbol encloses -- + // top-level statements, a test file's anonymous `test("...", () => ...)` + // blocks, a data module -- was in no document at all. The file's document is + // that residue (lines no other node's span covers, so nothing is counted + // twice) plus the terms of its path, which is how a file is usually named. + std::vector covered(static_cast(line_count) + 1, false); + for (const auto* node : nodes) { + if (node->kind == "file") continue; + const auto start = node->source_location->start_line; + const auto end = std::min(std::max(start, node->source_location->end_line), line_count); + for (auto line = start; line <= end; ++line) covered[line] = true; + } + const auto term_id = [&](const std::string& raw) { + const auto [entry, inserted] = vocabulary.try_emplace(stem_term(raw), static_cast(file.terms.size())); + if (inserted) { + file.terms.push_back(entry->first); + } + return entry->second; + }; + + std::vector counts; std::vector touched; + const auto count = [&](std::uint32_t term, BodyIndex::Doc& doc) { + if (counts.size() <= term) counts.resize(file.terms.size(), 0); + if (counts[term]++ == 0) { + touched.push_back(term); + } + ++doc.length; + }; file.docs.reserve(nodes.size()); for (const auto* node : nodes) { const auto start = node->source_location->start_line; @@ -190,12 +217,16 @@ void mix(std::uint64_t& hash, std::uint32_t value) { } BodyIndex::Doc doc; doc.node_id = node->id; - for (auto i = line_first_token[start - 1]; i < line_first_token[end]; ++i) { - const auto term = stream[i]; - if (counts[term]++ == 0) { - touched.push_back(term); + if (node->kind == "file") { + for (std::uint32_t line = 1; line <= line_count; ++line) { + if (covered[line]) continue; + for (auto i = line_first_token[line - 1]; i < line_first_token[line]; ++i) count(stream[i], doc); } - ++doc.length; + for_each_word(node->label, [&](std::string_view word) { + split_word(word, [&](const std::string& raw) { count(term_id(raw), doc); }); + }); + } else { + for (auto i = line_first_token[start - 1]; i < line_first_token[end]; ++i) count(stream[i], doc); } if (doc.length == 0) { continue; diff --git a/tests/smoke/body_index_test.cpp b/tests/smoke/body_index_test.cpp index 76ed474..499b3c4 100644 --- a/tests/smoke/body_index_test.cpp +++ b/tests/smoke/body_index_test.cpp @@ -137,6 +137,33 @@ int main() { expect(removed != respanned && removed->stats().files_tokenized == 0 && removed->stats().files == 1 && removed->stats().documents == 1, "an index over the remaining file only"); + // A file node's document is the text no symbol encloses plus its path: a + // test file's anonymous top-level blocks are otherwise in no document, and a + // named helper's body must not be counted a second time in the file's. + const auto spec = root / "widget.test.ts"; + const auto spec_text = write(spec, + "import { render } from './widget'\n" + "function mountFixture() {\n" + " return renderShadowRoot(paletteSwatch)\n" + "}\n" + "test('rejects an expired session token', () => {\n" + " expect(refreshCookie()).toThrow()\n" + "})\n"); + cgraph::GraphSnapshot files; + files.nodes = {cgraph::Node{.id = "spec_file", .label = "ui/widget.test.ts", .source_file = spec.generic_string(), + .source_location = cgraph::SourceLocation{.start_line = 1, .end_line = 1}, + .kind = "file"}, + fn("mountFixture", spec, 2, 4)}; + record(files, spec, spec_text); + const auto file_docs = cgraph::BodyIndex::refresh(files, nullptr); + expect(file_docs->stats().documents == 2, "the file node and its helper each have a document"); + expect(top(*file_docs, "expired session token cookie refresh") == "spec_file", + "top-level test block text belongs to the file's document"); + expect(top(*file_docs, "widget") == "spec_file", "path terms belong to the file's document"); + const auto swatch = file_docs->rank(cgraph::stem_terms(cgraph::lexical_terms("palette swatch shadow")), 5); + expect(swatch.size() == 1 && *swatch.front().second == "mountFixture", + "a symbol's body is not counted again in its file's document"); + // A snapshot without source hashes (a bare graph.json load) has nothing // verified to index. cgraph::GraphSnapshot unhashed; From a3f130df1e2fac5f262e978c19ed856f8153c3c7 Mon Sep 17 00:00:00 2001 From: Taylor Gagne Date: Sat, 17 Oct 2026 03:27:22 -0700 Subject: [PATCH 05/10] feat(context): a seed's tests are reached at depth 1 The tests edge hangs off the file node, a hop past a symbol seed, and test files carry little centrality, so context ranked every file the seed's file imports above the seed's own tests. Counterparts by a tests edge (a source seed's tests, or a test seed's subject) now enter at depth 1, the footing of the seed's file, in fixed and adaptive gathering alike. External dev set: R@20 0.7256 -> 0.7277, BCY@8k 0.5193 -> 0.5229. ARB dev split: MRR 0.4774 -> 0.4801, BCY@8k 0.6892 -> 0.6982. Co-Authored-By: Claude Opus 5.5 --- src/engine/daemon_ops.cpp | 29 +++++++++++++++++++++++ tests/smoke/daemon_ops_test.cpp | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/src/engine/daemon_ops.cpp b/src/engine/daemon_ops.cpp index aff2803..17e7282 100644 --- a/src/engine/daemon_ops.cpp +++ b/src/engine/daemon_ops.cpp @@ -1234,6 +1234,35 @@ struct StructuralIntent { } } + // A seed's own tests (or, for a test, the file it tests) are part of the unit + // being asked about, but the `tests` edge hangs off the file node, a hop past + // a symbol seed, and test files carry little centrality -- so depth-then- + // centrality ranks every imported file above them. Reach them at depth 1, the + // footing of the seed's own file. + { + std::unordered_map file_node_by_source; + for (const auto& node : graph.nodes) { + if (node.kind == "file" && !node.source_file.empty()) { + file_node_by_source.emplace(node.source_file, &node.id); + } + } + std::unordered_set seed_files; + for (const auto* seed : seeds) { + if (const auto file = file_node_by_source.find(seed->source_file); file != file_node_by_source.end()) { + seed_files.insert(*file->second); + } + } + for (const auto& edge : graph.edges) { + if (edge.relation != "tests") continue; + const std::string* counterpart = seed_files.contains(edge.source) ? &edge.target + : seed_files.contains(edge.target) ? &edge.source + : nullptr; + if (counterpart == nullptr) continue; + const auto [it, fresh] = reached.try_emplace(*counterpart, Reached{1, "tests"}); + if (!fresh && it->second.depth > 1) it->second = Reached{1, "tests"}; + } + } + // The graph has no direct sibling edge between otherwise-unrelated symbols in // one file. Under adaptive gathering only, admit siblings from the primary // focal's file as direct, query-ranked candidates. They do not enter `frontier`: diff --git a/tests/smoke/daemon_ops_test.cpp b/tests/smoke/daemon_ops_test.cpp index a895a2c..f428fb7 100644 --- a/tests/smoke/daemon_ops_test.cpp +++ b/tests/smoke/daemon_ops_test.cpp @@ -8,6 +8,7 @@ #include "cgraph/protocol.hpp" #include "cgraph/semantic_fragment_validation.hpp" +#include #include #include #include @@ -18,6 +19,7 @@ #include #include #include +#include int main() { namespace fs = std::filesystem; @@ -2512,5 +2514,45 @@ int main() { fs::remove_all(base); } + // --- a seed's tests are reached at depth 1 (CGR-38) --- + // `tests` hangs off the file node, a hop past a symbol seed, and a test file + // has little centrality, so it used to rank under every file the seed's file + // imports. It now sits with the seed's own file. + { + cgraph::DaemonState s; + cgraph::GraphSnapshot g; + g.build_state = cgraph::BuildState::DeterministicReady; + const auto file = [&](const std::string& id, const std::string& centrality) { + g.nodes.push_back(cgraph::Node{.id = id, .label = id, .source_file = "/r/" + id, .kind = "file", + .properties = {{"degree_centrality", centrality}}}); + }; + file("path.go", "0.300000"); + file("path_test.go", "0.010000"); + file("hub1.go", "0.900000"); + file("hub2.go", "0.800000"); + g.nodes.push_back(cgraph::Node{.id = "clean", .label = "cleanPath", .source_file = "/r/path.go", .kind = "function"}); + g.edges.push_back(cgraph::Edge{.source = "path.go", .target = "clean", .relation = "contains"}); + g.edges.push_back(cgraph::Edge{.source = "path.go", .target = "hub1.go", .relation = "imports"}); + g.edges.push_back(cgraph::Edge{.source = "path.go", .target = "hub2.go", .relation = "imports"}); + g.edges.push_back(cgraph::Edge{.source = "path_test.go", .target = "path.go", .relation = "tests"}); + cgraph::publish_graph_snapshot(s, std::move(g)); + + for (const char* gather : {"fixed", "adaptive"}) { + const auto r = cgraph::handle_daemon_request( + s, cgraph::make_request("context", {{"id", "clean"}, {"budget", 5000}, {"gather", gather}})); + const auto& included = r["result"]["included"]; + std::vector order; + int test_depth = -1; + for (const auto& item : included) { + order.push_back(item.value("label", std::string{})); + if (order.back() == "path_test.go") test_depth = item.value("depth", -1); + } + const auto at = [&](const std::string& label) { return std::ranges::find(order, label) - order.begin(); }; + if (test_depth != 1 || at("path_test.go") > at("hub1.go") || at("path_test.go") > at("hub2.go")) { + return 130; + } + } + } + return 0; } From 053aba3bea78a31119e3b68edf4caf61f65da463 Mon Sep 17 00:00:00 2001 From: Taylor Gagne Date: Sat, 17 Oct 2026 03:33:57 -0700 Subject: [PATCH 06/10] bench(arb): anchors vote once in the fused ranking Each anchor op list (one per implementation file or quoted path) had its own RRF vote, so correlated anchors (build-tag twins, sibling locale files) outvoted the query's own lists: zod's parity.test.ts was rank 1 in both text lists and fused to 43. The anchor lists are now fused among themselves and vote once (cgraph_eval.fuse, shared with ablation.py). ablation.py also tolerates a split run with no sample of a task. External dev set: R@20 0.7277 -> 0.7418, MRR 0.3792 -> 0.4101, BCY@8k 0.5229 -> 0.5517. ARB dev split: R@20 0.8979 -> 0.8934, MRR 0.4801 -> 0.4797, BCY flat. Co-Authored-By: Claude Opus 5.5 --- bench/arb/ablation.py | 15 +++++++++++---- bench/arb/cgraph_eval.py | 14 +++++++++++++- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/bench/arb/ablation.py b/bench/arb/ablation.py index 4961bb9..ed84eb7 100644 --- a/bench/arb/ablation.py +++ b/bench/arb/ablation.py @@ -23,7 +23,7 @@ "query(q) only": lambda lists: [lists["query_text"]], "context(q) + query(q)": lambda lists: [lists["context_text"], lists["query_text"]], "anchor ops only": lambda lists: [v for k, v in lists.items() if k.startswith("context_anchor") or k == "impact_changed"], - "all ops (scored recipe)": lambda lists: list(lists.values()), + "all ops, one vote each": lambda lists: list(lists.values()), } @@ -46,9 +46,13 @@ def main(argv: list[str] | None = None) -> int: candidates[chunks] = set(bcy_curve.load_file_texts(chunks)) files = candidates[chunks] gold = set(row["gold_files"]) - for name, pick in VARIANTS.items(): - lists = pick(row["cgraph"]["lists"]) - ranked = [p for p in cgraph_eval.rrf(lists) if p in files] if lists else [] + for name, pick in [*VARIANTS.items(), ("scored recipe (cgraph_eval.fuse)", None)]: + if pick is None: + fused = cgraph_eval.fuse(row["cgraph"]["lists"]) + else: + lists = pick(row["cgraph"]["lists"]) + fused = cgraph_eval.rrf(lists) if lists else [] + ranked = [p for p in fused if p in files] recall = len(gold & set(ranked[:20])) / len(gold) rr = next((1.0 / i for i, p in enumerate(ranked, start=1) if p in gold), 0.0) scores[name]["overall"].append((recall, rr)) @@ -60,6 +64,9 @@ def main(argv: list[str] | None = None) -> int: cells = [] for g in groups: vals = by_group[g] + if not vals: # a split run (--split dev) can hold no sample of a task + cells.append("-") + continue cells.append(f"{sum(v[0] for v in vals) / len(vals):.4f} / {sum(v[1] for v in vals) / len(vals):.4f}") print(f"| {name} | " + " | ".join(cells) + " |") return 0 diff --git a/bench/arb/cgraph_eval.py b/bench/arb/cgraph_eval.py index f7ed97a..9645a53 100644 --- a/bench/arb/cgraph_eval.py +++ b/bench/arb/cgraph_eval.py @@ -317,6 +317,18 @@ def rrf(lists: list[list[str]]) -> list[str]: return sorted(score, key=lambda p: (-score[p], first[p], p)) +def fuse(lists: dict[str, list[str]]) -> list[str]: + """The scored recipe: every op list votes once by RRF, except the anchors. + They are views of one change (two build-tag twins, three locale files) whose + near-identical lists outvoted the query's own lists one vote each, so they + are fused among themselves first and vote once (CGR-38).""" + anchor_lists = [v for k, v in lists.items() if k.startswith("context_anchor_")] + voices = [v for k, v in lists.items() if not k.startswith("context_anchor_")] + if anchor_lists: + voices.append(rrf(anchor_lists)) + return rrf(voices) + + def retrieve(daemon: Daemon, sample: dict[str, Any], index: SnapshotIndex, files: set[str]) -> dict[str, Any]: prefix = str(daemon.root.resolve()) + "/" text = query_text(sample) @@ -347,7 +359,7 @@ def retrieve(daemon: Daemon, sample: dict[str, Any], index: SnapshotIndex, files impacted.sort(key=lambda node: int(node.get("depth") or 0)) # stable: per-seed order kept within a depth lists["impact_changed"] = node_files(impacted, prefix) - fused = rrf(list(lists.values())) + fused = fuse(lists) in_candidates = [path for path in fused if path in files] ops["dropped_non_candidate"] = len(fused) - len(in_candidates) return {"ranked_files": in_candidates, "lists": {k: v[:50] for k, v in lists.items()}, "ops": ops} From 4a93da70447106434bf58551f44aae6ae35a8b82 Mon Sep 17 00:00:00 2001 From: Taylor Gagne Date: Sun, 18 Oct 2026 22:44:57 -0700 Subject: [PATCH 07/10] fix(graph): a test outside any test root pairs only in its own directory Review found the package scope empty for a test outside a test root, so the unique-stem step matched anywhere: caddy got reverseproxy/headers_test.go -> headers/headers.go and integration/handler_test.go -> push/handler.go, which impact and context then served. A test outside a test root now pairs only beside its subject; stems exactly test/tests count as tests (Rust tests.rs modules are never subjects); context's counterpart rule honours max_depth 0. Tests: cross-directory and tests.rs cases, max_depth 0, and incremental vs one-shot parity on a tree with a test file. Dev split and external dev set scores unchanged. Co-Authored-By: Claude Opus 5.5 --- src/engine/daemon_ops.cpp | 4 ++-- src/engine/graph_builder.cpp | 12 +++++++++--- src/engine/include/cgraph/graph_builder.hpp | 7 ++++--- tests/smoke/daemon_ops_test.cpp | 6 ++++++ tests/smoke/graph_builder_test.cpp | 9 +++++++++ tests/smoke/incremental_update_test.cpp | 12 ++++++++++++ 6 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/engine/daemon_ops.cpp b/src/engine/daemon_ops.cpp index 17e7282..99b95f6 100644 --- a/src/engine/daemon_ops.cpp +++ b/src/engine/daemon_ops.cpp @@ -1238,8 +1238,8 @@ struct StructuralIntent { // being asked about, but the `tests` edge hangs off the file node, a hop past // a symbol seed, and test files carry little centrality -- so depth-then- // centrality ranks every imported file above them. Reach them at depth 1, the - // footing of the seed's own file. - { + // footing of the seed's own file. A radius of 0 asks for the seed alone. + if (max_depth >= 1) { std::unordered_map file_node_by_source; for (const auto& node : graph.nodes) { if (node.kind == "file" && !node.source_file.empty()) { diff --git a/src/engine/graph_builder.cpp b/src/engine/graph_builder.cpp index 0452997..2a6e48f 100644 --- a/src/engine/graph_builder.cpp +++ b/src/engine/graph_builder.cpp @@ -1731,8 +1731,8 @@ void resolve_test_subjects(GraphSnapshot& graph) { // outside a test directory still counts; Java's `XTest` is left to // is_test_source_path, which guards it against `ABTest`. const auto named_as_test = [](std::string_view stem) { - return stem.starts_with("test_") || stem.ends_with("_test") || stem.ends_with("_tests") || - stem.ends_with(".test") || stem.ends_with(".spec") || stem.ends_with("_spec"); + return stem == "test" || stem == "tests" || stem.starts_with("test_") || stem.ends_with("_test") || + stem.ends_with("_tests") || stem.ends_with(".test") || stem.ends_with(".spec") || stem.ends_with("_spec"); }; const auto test_root_segment = [](std::string_view segment) { return segment == "test" || segment == "tests" || segment == "__tests__" || segment == "spec" || @@ -1742,12 +1742,13 @@ void resolve_test_subjects(GraphSnapshot& graph) { // root segment removed. `package` is what precedes the first test root // (`clap_complete/` for `clap_complete/tests/x.rs`): a package's tests test it. struct TestLocation { + bool in_test_root = false; std::string mirror; std::string_view package; }; const auto locate = [&](std::string_view dir) { TestLocation out; - bool in_test_root = false; + bool& in_test_root = out.in_test_root; std::size_t start = 0; while (start <= dir.size()) { const auto end = std::min(dir.find('/', start), dir.size()); @@ -1838,7 +1839,12 @@ void resolve_test_subjects(GraphSnapshot& graph) { if (linked || generic_stem(core)) { continue; } + // A test outside any test root (`pkg/headers_test.go`) sits beside the code + // it tests by convention; a same-named file elsewhere is a guess. const auto location = locate(dir); + if (!location.in_test_root) { + continue; + } std::vector candidates; for (const auto& candidate : found->second) { if (candidate.relative.starts_with(location.package)) candidates.push_back(&candidate); diff --git a/src/engine/include/cgraph/graph_builder.hpp b/src/engine/include/cgraph/graph_builder.hpp index bac0d4d..edd6287 100644 --- a/src/engine/include/cgraph/graph_builder.hpp +++ b/src/engine/include/cgraph/graph_builder.hpp @@ -83,9 +83,10 @@ void resolve_interface_dispatch(GraphSnapshot& graph, std::span r // its name pairs with (`path_test.go` -> `path.go`, `test_core.py` -> `core.py`, // `button.spec.ts` -> `button.ts`, `tests/help.rs` -> `src/help.rs`). Calls // from a test reach its subject only when call resolution is unambiguous, so -// without this most tests are islands. Beyond the test's own directory a pair -// must be the unique match inside the test's package (what precedes its test -// root) or the one file in the directory its test-root-free path mirrors. +// without this most tests are islands. A test outside any test-root directory +// pairs only within its own directory. One under a test root may also pair with +// the unique match inside its package (what precedes the test root) or the one +// file in the directory its test-root-free path mirrors. // Generic names (`main`, `mod`, `index`, `utils`...) pair only in-directory, // and example/doc/bench files are never subjects. void resolve_test_subjects(GraphSnapshot& graph); diff --git a/tests/smoke/daemon_ops_test.cpp b/tests/smoke/daemon_ops_test.cpp index f428fb7..928b61c 100644 --- a/tests/smoke/daemon_ops_test.cpp +++ b/tests/smoke/daemon_ops_test.cpp @@ -2552,6 +2552,12 @@ int main() { return 130; } } + // max_depth 0 asks for the seed alone; its tests are a hop away. + const auto alone = cgraph::handle_daemon_request( + s, cgraph::make_request("context", {{"id", "clean"}, {"budget", 5000}, {"max_depth", 0}})); + if (!alone["result"]["included"].empty()) { + return 131; + } } return 0; diff --git a/tests/smoke/graph_builder_test.cpp b/tests/smoke/graph_builder_test.cpp index 4beb9e3..9730257 100644 --- a/tests/smoke/graph_builder_test.cpp +++ b/tests/smoke/graph_builder_test.cpp @@ -1047,6 +1047,13 @@ int test_resolve_test_subjects() { const auto example_main = file("examples/demo/main.rs"); const auto completion_test = file("other/tests/completion.rs"); const auto example_completion = file("lib/examples/completion.rs"); + // Outside a test root a test pairs only beside its subject: reverseproxy's + // headers_test.go is not a test of the headers module. + const auto headers = file("modules/headers/headers.go"); + const auto proxy_headers_test = file("modules/reverseproxy/headers_test.go"); + // A Rust `tests.rs` unit-test module is a test, never a test's subject. + const auto builder_tests = file("src/builder/tests.rs"); + const auto suite_tests = file("tests/builder/tests.rs"); const auto plain = file("server.go"); cgraph::resolve_test_subjects(graph); @@ -1063,6 +1070,8 @@ int test_resolve_test_subjects() { if (!has_edge(graph, widget_test, widget_a, "tests") || has_edge(graph, widget_test, widget_b, "tests")) return 1; if (has_edge(graph, suite_main, example_main, "tests")) return 1; if (has_edge(graph, completion_test, example_completion, "tests")) return 1; + if (has_edge(graph, proxy_headers_test, headers, "tests")) return 1; + if (has_edge(graph, suite_tests, builder_tests, "tests")) return 1; (void)lonely_test; (void)plain; if (tests_edges != 5) { diff --git a/tests/smoke/incremental_update_test.cpp b/tests/smoke/incremental_update_test.cpp index 71448fd..8081ec2 100644 --- a/tests/smoke/incremental_update_test.cpp +++ b/tests/smoke/incremental_update_test.cpp @@ -5,6 +5,7 @@ #include "cgraph/daemon_ops.hpp" #include "cgraph/pipeline.hpp" +#include #include #include #include @@ -224,6 +225,14 @@ int main() { return 1; } + // A test file next to beta.py gets the same `tests` edge from the daemon's + // rebuild as from the one-shot pipeline (both run resolve_test_subjects). + write_file(root / "test_beta.py", "def test_delta():\n assert True\n"); + result = cgraph::full_stat_index_rescan(state, index, root); + const auto tests_edges = [](const cgraph::GraphSnapshot& g) { + return std::count_if(g.edges.begin(), g.edges.end(), [](const cgraph::Edge& e) { return e.relation == "tests"; }); + }; + // The daemon's rescan must produce the same graph as the canonical one-shot // pipeline: identical labels AND identical node/edge counts. The count check // guards the pipeline ordering — the daemon must dedup before community @@ -238,6 +247,9 @@ int main() { graph->edges.size() != full_build.graph.edges.size()) { return 1; } + if (tests_edges(*graph) != 1 || tests_edges(full_build.graph) != 1) { + return 1; + } // The daemon graph carries community + centrality (computed after dedup), so // ranked queries work on the resident snapshot. bool has_centrality = false; From 67f994c7bf6f66587a11ef777c4f2a33cf5ba11f Mon Sep 17 00:00:00 2001 From: Taylor Gagne Date: Sun, 18 Oct 2026 22:45:56 -0700 Subject: [PATCH 08/10] docs(openspec): test-subjects-and-file-documents change Specs for the tests edge pass, file body documents and context's depth-1 test counterparts (CGR-38). openspec validate --strict passes. Co-Authored-By: Claude Opus 5.5 --- .../proposal.md | 39 +++++++++++++++++++ .../deterministic-graph-pipeline/spec.md | 28 +++++++++++++ .../specs/graph-daemon-client/spec.md | 28 +++++++++++++ .../test-subjects-and-file-documents/tasks.md | 28 +++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 openspec/changes/test-subjects-and-file-documents/proposal.md create mode 100644 openspec/changes/test-subjects-and-file-documents/specs/deterministic-graph-pipeline/spec.md create mode 100644 openspec/changes/test-subjects-and-file-documents/specs/graph-daemon-client/spec.md create mode 100644 openspec/changes/test-subjects-and-file-documents/tasks.md diff --git a/openspec/changes/test-subjects-and-file-documents/proposal.md b/openspec/changes/test-subjects-and-file-documents/proposal.md new file mode 100644 index 0000000..bfb7a98 --- /dev/null +++ b/openspec/changes/test-subjects-and-file-documents/proposal.md @@ -0,0 +1,39 @@ +## Why + +CGraph's Agent Retrieval Bench (ARB) result was tuned on 40 ARB samples (CGR-25). On the 234 +samples from the other 22 repositories it trailed RepoMap on Recall@20 and BCY@8k (CGR-38). The +losses were in code2test (find the tests for a change) and edit2ripple (find what an edit +ripples into), and three engine gaps explained them: + +- A test file reached its subject only when a call from the test resolved unambiguously, so most + test files were islands: neither `context` nor `impact` from a source file reached its tests. +- A file node's span is its first line, so text no symbol encloses (top-level statements, a test + file's anonymous `test("...", () => ...)` blocks, data modules) was in no BM25 document, and + neither was the file's path. +- Once linked, a test file still ranked under every file its subject imports: `context` orders by + depth then centrality, the `tests` edge hangs off the file node a hop past a symbol seed, and + test files carry little centrality. + +## What Changes + +- Build pass `resolve_test_subjects` (one-shot and incremental): an inferred `tests` edge from + each test file to the source file its name pairs with (`path_test.go` -> `path.go`, + `test_core.py` -> `core.py`, `button.spec.ts` -> `button.ts`, `tests/help.rs` -> `src/help.rs`). + A test outside any test-root directory pairs only within its own directory. One under a test + root may also pair with the unique match inside its package (what precedes the test root) or the + one file in the directory its test-root-free path mirrors. Generic names (`main`, `mod`, `lib`, + `index`, `__init__`, `utils`...) pair only in-directory; example, doc and bench files are never + subjects. `stem_of`/`test_core` move next to `is_test_source_path` and are shared with co-change. +- Body index: a file node's document is the lines no other node's span covers plus its path terms. + Symbol documents are unchanged and nothing is counted twice. +- `context`: a seed file's `tests` counterparts enter at depth 1 (`via = "tests"`), unless + `max_depth` is 0. +- Index version key `logic-26`. +- ARB harness: a declared dev/held-out split (`score.py --split`, `cgraph_eval.py --split`), and + the per-file anchor op lists are fused among themselves before they vote (`cgraph_eval.fuse`). + +## Impact + +`impact` dependents of a source file now include its tests at depth 1, and `path` may route +through a test file. Reports (modules, clones, types) and the pre-edit hook's cross-service query +use relation allowlists and are unaffected. diff --git a/openspec/changes/test-subjects-and-file-documents/specs/deterministic-graph-pipeline/spec.md b/openspec/changes/test-subjects-and-file-documents/specs/deterministic-graph-pipeline/spec.md new file mode 100644 index 0000000..6b92f11 --- /dev/null +++ b/openspec/changes/test-subjects-and-file-documents/specs/deterministic-graph-pipeline/spec.md @@ -0,0 +1,28 @@ +## ADDED Requirements + +### Requirement: Test files link to the source file they test +After call, relation, contract and interface-dispatch resolution, the pipeline (one-shot and +incremental alike) SHALL add an inferred `tests` edge from each test file node to the source file +node its name pairs with. A test file SHALL be one `is_test_source_path` classifies by its +repo-relative path, or whose stem is `test`/`tests` or carries a test marker (`test_x`, `x_test`, +`x_tests`, `x.test`, `x.spec`, `x_spec`). The pair SHALL be the non-test file whose stem equals the +test's stem with one marker removed. A pair in the test's own directory SHALL always link. Beyond +it, only a test under a test-root directory (`test`, `tests`, `__tests__`, `spec`, `specs`, `e2e`, +`integrationTest`) MAY link, and only to the unique matching file inside its package (the path +before the first test root), else to the one matching file in the directory its test-root-free +path mirrors. Generic stems (`main`, `mod`, `lib`, `index`, `__init__`, `utils`, `util`, +`helpers`, `common`, `conftest`, `setup`) SHALL pair only in-directory, and files under +`examples`, `example`, `docs`, `doc`, `benches`, `bench` or `benchmarks` SHALL never be subjects. +Anything else SHALL produce no edge. Re-running the pass SHALL add nothing. + +#### Scenario: A Go test links to the file beside it +- **WHEN** `path_test.go` and `path.go` share a directory +- **THEN** the graph has `path_test.go -tests-> path.go` + +#### Scenario: A same-named file in another package is not a guess +- **GIVEN** `modules/reverseproxy/headers_test.go` and a lone `modules/headers/headers.go` +- **THEN** no `tests` edge joins them + +#### Scenario: A test under a test root mirrors its subject's directory +- **GIVEN** `tests/http/test_client.py`, `http/client.py` and `db/client.py` +- **THEN** the test links to `http/client.py` only diff --git a/openspec/changes/test-subjects-and-file-documents/specs/graph-daemon-client/spec.md b/openspec/changes/test-subjects-and-file-documents/specs/graph-daemon-client/spec.md new file mode 100644 index 0000000..df15ba5 --- /dev/null +++ b/openspec/changes/test-subjects-and-file-documents/specs/graph-daemon-client/spec.md @@ -0,0 +1,28 @@ +## ADDED Requirements + +### Requirement: A file's body document covers its unenclosed text and path +The body index SHALL give each indexed file node a document made of the terms on lines no other +indexed node's span in that file covers, plus the terms of the file node's label (its +repo-relative path). Symbol documents SHALL be unchanged, so no line's terms count in both a +symbol's document and its file's. + +#### Scenario: An anonymous top-level test block is searchable +- **GIVEN** a test file whose cases are anonymous `test('...', () => ...)` callbacks +- **WHEN** a prose query uses words from one of those cases +- **THEN** the file node ranks by its body document + +#### Scenario: A symbol's body is not counted twice +- **WHEN** a query's terms appear only inside a named function's span +- **THEN** that function's document matches and its file's document does not + +### Requirement: Context reaches a seed's tests at depth 1 +When `max_depth` is at least 1, `context` SHALL admit every file node joined by a `tests` edge to +a seed's file node (a source seed's tests, or a test seed's subject) at depth 1 with +`via = "tests"`, keeping a shallower depth already reached. Admitted counterparts SHALL NOT be +expanded further. With `max_depth` 0 nothing SHALL be admitted. + +#### Scenario: A symbol's test file outranks its file's imports +- **GIVEN** `cleanPath` in `path.go`, which imports two high-centrality files, and + `path_test.go -tests-> path.go` +- **WHEN** `context` is requested for `cleanPath` +- **THEN** `path_test.go` is included at depth 1, ahead of both imported files diff --git a/openspec/changes/test-subjects-and-file-documents/tasks.md b/openspec/changes/test-subjects-and-file-documents/tasks.md new file mode 100644 index 0000000..e835c7c --- /dev/null +++ b/openspec/changes/test-subjects-and-file-documents/tasks.md @@ -0,0 +1,28 @@ +# Tasks + +## 1. Graph + +- [x] 1.1 `resolve_test_subjects` in one-shot and incremental builds; shared `stem_of`/`test_core`; + `common_source_root` replaces the inline root derivation in contracts. +- [x] 1.2 Pairing scope: in-directory always; package-unique or mirrored only under a test root; + generic stems in-directory only; examples/docs/benches never subjects. +- [x] 1.3 Index version key `logic-26`. + +## 2. Search and context + +- [x] 2.1 File node body document: uncovered lines + path terms. +- [x] 2.2 `context` admits `tests` counterparts of seed files at depth 1; none at `max_depth` 0. + +## 3. Tests + +- [x] 3.1 graph_builder_test: pairing rules, idempotence, root under a `tests` directory. +- [x] 3.2 body_index_test: file documents, no double counting, path terms. +- [x] 3.3 daemon_ops_test: counterpart depth and order, `max_depth` 0 (fails without the change). +- [x] 3.4 incremental_update_test: incremental and one-shot agree on `tests` edges. + +## 4. Benchmark (CGR-38) + +- [x] 4.1 Declared split (`score.py`/`cgraph_eval.py --split`) committed before tuning. +- [x] 4.2 External dev set from 10 repositories outside ARB, built with ARB's own miners. +- [x] 4.3 Anchor op lists vote once (`cgraph_eval.fuse`). +- [ ] 4.4 Held-out score on a released binary; bench/arb/RESULTS.md section. From 87095cfd6de2319744375d9bb30c51831dfbb46b Mon Sep 17 00:00:00 2001 From: Taylor Gagne Date: Sun, 18 Oct 2026 22:59:34 -0700 Subject: [PATCH 09/10] bench(arb): CGR-38 results section (branch build, pending release) Co-Authored-By: Claude Opus 5.5 --- bench/arb/RESULTS.md | 74 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/bench/arb/RESULTS.md b/bench/arb/RESULTS.md index 4a9de59..516a778 100644 --- a/bench/arb/RESULTS.md +++ b/bench/arb/RESULTS.md @@ -6,6 +6,80 @@ The benchmark is [Agent Retrieval Bench](https://arxiv.org/abs/2607.24882) (ARB, repository is checked out at its base commit, because ARB's released corpus is chunked and truncated and CGraph has to index the real tree. +## CGR-38: tuned without ARB samples (branch build, pending release) + +bin-v0.9.1's numbers below were tuned on a 40-sample ARB subset (clap, caddy, gin). This section +reports work done without that: every change was developed on a declared dev side and the rest of +ARB was scored only to measure it. + +**Protocol.** + +- **Split, declared before any change** (`score.py` `DEV_REPOS`, commit bee900e). Dev = every + gin, caddy and clap sample (111, a superset of CGR-25's 40). Held-out = the other 234 samples + from 22 repositories. +- **External dev set.** The ARB dev split has no comment2context and only 19 code2test samples, + so it cannot drive tuning on its own. A second dev set was built with ARB's own miners at the + pinned commit from 10 repositories ARB never used (`extdev/`): 229 code2test and 187 + edit2ripple samples. +- **Held-out looks.** All diagnosis used dev and extdev only; held-out samples were never + inspected one by one. Held-out aggregates were read three times: + 1. the bin-v0.9.5 baseline, before any change; + 2. the branch build below; + 3. the released binary. + + One earlier held-out run of a pre-review build lost a snapshot to a host memory fault and was + discarded without its scores being read. + +**Changes** (openspec `test-subjects-and-file-documents`): + +1. **`tests` edges.** Each test file is linked to the source file its name pairs with. +2. **File body documents.** A file node's BM25 document is now its text outside any symbol, plus + its path. +3. **Tests in context.** `context` reaches a seed's tests at depth 1. +4. **Anchor fusion (harness).** The per-file anchor op lists are fused among themselves and vote + once, not once per file. + +| Held-out, 234 samples | R@20 | MRR | BCY@8k | +|---|---:|---:|---:| +| RepoMap (rerun) | 0.5402 | 0.1785 | 0.3363 | +| CGraph bin-v0.9.5 | 0.5164 | 0.2076 | 0.3184 | +| **CGraph branch** | **0.5628** | **0.2076** | **0.3167** | + +Against RepoMap on held-out: + +- R@20 is +0.0226 and MRR +0.0291, both outside the noise floor. +- BCY@8k is -0.0196. + +By task: + +| Held-out task | n | RepoMap R@20 / MRR / BCY@8k | CGraph branch R@20 / MRR / BCY@8k | +|---|---:|---|---| +| code2test | 87 | 0.4950 / 0.1667 / 0.3280 | 0.4927 / 0.1516 / 0.2188 | +| comment2context | 80 | 0.4708 / 0.1527 / 0.2896 | 0.5125 / 0.2223 / 0.3104 | +| trace2code | 37 | 0.8829 / 0.2773 / 0.5270 | 0.8694 / 0.3094 / 0.5811 | +| edit2ripple | 30 | 0.4333 / 0.1597 / 0.2500 | 0.5222 / 0.2054 / 0.2917 | + +What changed against bin-v0.9.5 on held-out: + +- **code2test** gains the most: R@20 0.3870 to 0.4927. +- **trace2code** falls: MRR 0.3551 to 0.3094, BCY@8k 0.6261 to 0.5811. The extra test files now + compete with the source files a stack trace names. This is why overall MRR is flat. + +| All 345 samples | R@20 | MRR | BCY@8k | +|---|---:|---:|---:| +| RepoMap (rerun) | 0.6311 | 0.2156 | 0.3846 | +| CGraph bin-v0.9.5 | 0.6353 | 0.2759 | 0.4309 | +| **CGraph branch** | **0.6692** | **0.2951** | **0.4395** | + +Dev sides, for reference (both were used for tuning, so they are not evidence on their own): + +| | n | bin-v0.9.5 R@20 / MRR / BCY@8k | branch R@20 / MRR / BCY@8k | RepoMap R@20 / MRR / BCY@8k | +|---|---:|---|---|---| +| ARB dev (gin, caddy, clap) | 111 | 0.8859 / 0.4199 / 0.6682 | 0.8934 / 0.4797 / 0.6982 | 0.8228 / 0.2939 / 0.4865 | +| External dev set | 416 | 0.6891 / 0.3119 / 0.4752 | 0.7418 / 0.4101 / 0.5517 | 0.8099 / 0.4543 / 0.5815 | + +On the external dev set CGraph still trails RepoMap on every metric. + ## bin-v0.9.1 (BM25 code-text search, CGR-25) Same harness and data pins as below, engine release bin-v0.9.1 (`cgraph --version`: From c374a8d3e30ca12a344f68c1c8516eed146e821f Mon Sep 17 00:00:00 2001 From: Taylor Gagne Date: Sun, 18 Oct 2026 23:03:08 -0700 Subject: [PATCH 10/10] bench(arb): commit the external dev set and score.py --tasks Add bench/arb/extdev/: the 10-repo external dev set (v2_code2test 229 samples, v2_edit2ripple 187) mined with ARB's own miners, its four builder scripts, and a README with the pipeline, funnel tables, audit substitute, deviations and baseline scores. The chunked corpus and snapshot caches are regenerable (ARB build-corpus plus bench/arb/snapshots.py) and not committed. crawl_repo.sh now takes its work dir from ARB_WORK. score.py gains --tasks (default all four) so the scorer works on a dataset with only some tasks. Default output is byte-identical to before; on extdev it reproduces the numbers of the earlier task-trimmed copy exactly. Co-Authored-By: Claude Opus 5.5 --- bench/arb/extdev/.gitignore | 3 + bench/arb/extdev/README.md | 204 ++++++++++++++++ .../data/benchmark/v2_code2test/manifest.json | 85 +++++++ .../data/benchmark/v2_code2test/samples.jsonl | 229 ++++++++++++++++++ .../benchmark/v2_edit2ripple/manifest.json | 85 +++++++ .../benchmark/v2_edit2ripple/samples.jsonl | 187 ++++++++++++++ bench/arb/extdev/scripts/consistent_raw.py | 65 +++++ bench/arb/extdev/scripts/crawl_repo.sh | 17 ++ bench/arb/extdev/scripts/fetch_pr_metadata.py | 46 ++++ bench/arb/extdev/scripts/finalize.py | 145 +++++++++++ bench/arb/score.py | 44 ++-- 11 files changed, 1094 insertions(+), 16 deletions(-) create mode 100644 bench/arb/extdev/.gitignore create mode 100644 bench/arb/extdev/README.md create mode 100644 bench/arb/extdev/data/benchmark/v2_code2test/manifest.json create mode 100644 bench/arb/extdev/data/benchmark/v2_code2test/samples.jsonl create mode 100644 bench/arb/extdev/data/benchmark/v2_edit2ripple/manifest.json create mode 100644 bench/arb/extdev/data/benchmark/v2_edit2ripple/samples.jsonl create mode 100644 bench/arb/extdev/scripts/consistent_raw.py create mode 100755 bench/arb/extdev/scripts/crawl_repo.sh create mode 100644 bench/arb/extdev/scripts/fetch_pr_metadata.py create mode 100644 bench/arb/extdev/scripts/finalize.py diff --git a/bench/arb/extdev/.gitignore b/bench/arb/extdev/.gitignore new file mode 100644 index 0000000..59fa06a --- /dev/null +++ b/bench/arb/extdev/.gitignore @@ -0,0 +1,3 @@ +# finalize.py writes .jsonl as a byte copy of samples.jsonl. +data/benchmark/*/code2test.jsonl +data/benchmark/*/edit2ripple.jsonl diff --git a/bench/arb/extdev/README.md b/bench/arb/extdev/README.md new file mode 100644 index 0000000..2b42c46 --- /dev/null +++ b/bench/arb/extdev/README.md @@ -0,0 +1,204 @@ +# ARB external dev set (extdev), CGR-38 + +A dev set built the way Agent Retrieval Bench (ARB) builds its data, from 10 repositories ARB never used. It exists so CGraph's retrieval can be tuned without touching any ARB sample, which keeps the "no tuning on ARB" claim checkable. It has two tasks: `v2_code2test` (229 samples) and `v2_edit2ripple` (187 samples). The rows were mined by ARB's own deterministic miners at the commit pinned in `bench/arb/run.sh` (`ARB_COMMIT`). Built 2026-10-17. No LLM calls were made at any step. + +`$ARB_WORK` below is `run.sh`'s work dir (default `~/.cache/cgraph-arb`). ARB is checked out at `$ARB_WORK/arb`. + +## Layout + +Committed here: + +``` +bench/arb/extdev/ + data/benchmark/v2_code2test/{samples.jsonl,manifest.json} + data/benchmark/v2_edit2ripple/{samples.jsonl,manifest.json} + scripts/{fetch_pr_metadata.py,crawl_repo.sh,consistent_raw.py,finalize.py} +``` + +Not committed (large, regenerable, see "How to regenerate the corpus"): `data/corpus/` (chunked file texts, 202 and 113 commit corpora), `repos/` (bare snapshot caches), `baselines/`, `runs/`, `work/` (raw crawl and intermediate miner output). + +`finalize.py` also writes `.jsonl`, a byte copy of `samples.jsonl`; it is git-ignored. Each `chunks_path` in a corpus manifest is relative to the directory that holds `data/`, the same convention as the released manifests. So the regenerated tree lives in `$ARB_WORK/extdev/`. + +## How to regenerate the corpus + +```bash +export ARB_WORK=${ARB_WORK:-$HOME/.cache/cgraph-arb} +export PYTHONPATH=$ARB_WORK/arb/src PYTHONHASHSEED=0 +EXT=$ARB_WORK/extdev +mkdir -p $EXT && cp -r bench/arb/extdev/data $EXT/ && cd $EXT + +# 1. Bare snapshot caches for every base commit the samples name (needs network). +python3 /bench/arb/snapshots.py --cache repos --jobs 4 data/benchmark/*/samples.jsonl + +# 2. ARB's corpus builder on the committed samples (reads the bare caches). +for t in code2test edit2ripple; do + python3 -m agent_retrieval_bench.cli build-corpus data/benchmark/v2_$t/samples.jsonl \ + --repos-dir repos --out data/corpus/v2_$t --no-keep-list +done +``` + +`snapshots.py` takes `--cache DIR`, `--jobs N` and one or more `samples.jsonl` files; it makes one bare repo per upstream repo at `/__.git`, the layout `build-corpus --repos-dir` reads. + +## Running CGraph and scoring + +```bash +cd $EXT +python3 /bench/arb/cgraph_eval.py --arb-src ../arb --data data --cache repos \ + --work /tmp/cgraph-arb-extdev-snapshots --out runs/cgraph- --cgraph-bin-dir \ + --tasks code2test edit2ripple +python3 /bench/arb/score.py --arb-src ../arb --data data --tasks code2test edit2ripple \ + --out runs/cgraph-/results.json --markdown runs/cgraph-/results.md \ + CGraph=runs/cgraph- RepoMap=baselines:repomap Lexical=baselines:lexical BM25=baselines:bm25 +``` + +`--tasks` makes the scorer work on a dataset with only some tasks. Use the default `--split all`: `DEV_REPOS` in `score.py` names ARB repos, so it has no meaning here. For the baselines, run `run.sh` step 4 (`eval-repomap`, `eval-baseline --ranker lexical|bm25`, all with `--candidate-filter all_files --no-keep-list`) on `data/benchmark/v2_` and `data/corpus/v2_`, writing to `baselines/`. + +## Repositories + +prometheus/prometheus, labstack/echo, spf13/cobra, sharkdp/bat, psf/black, Textualize/rich, honojs/hono, colinhacks/zod, nushell/nushell, tokio-rs/axum. + +hyperium/hyper and BurntSushi/ripgrep were first proposed. Neither appears in released samples or in ARB's PLAN.md, but both are in ARB's `configs/crawl_targets.json` `"reserve"` list. They were swapped for nushell/nushell and tokio-rs/axum, which keeps the Rust share. None of the 10 final repos appears in the released samples (`jq -r .repo data/benchmark/v2_*/samples.jsonl`), in PLAN.md, or under ARB's `configs/ docs/ scripts/ src/ tests/` (checked with grep). + +## Pipeline + +Run from `$ARB_WORK/extdev/work` with `PYTHONPATH=$ARB_WORK/arb/src PYTHONHASHSEED=0` and a GitHub token in `GH_TOKEN` or `GITHUB_TOKEN`. `arb` means `python3 -m agent_retrieval_bench.cli`. The scripts write their JSON summaries and logs under `work/` (for example `work/logs/`). + +1. **PR metadata (GraphQL only).** `scripts/fetch_pr_metadata.py --raw raw --repo R --limit-prs 250`. It calls ARB's own `crawler._fetch_merged_prs_graphql` (MERGED_PR_QUERY, `pullRequests(states: MERGED ... orderBy: UPDATED_AT DESC)`) with crawl's default `--max-changed-files 20`. It writes the same `{"type": "pull_request", ...}` record `crawl_repo` writes, through ARB's `_upsert_jsonl`. It does not make crawl's per-PR REST calls (files, comments, commits, per-commit details). Total cost was about 60 GraphQL points. +2. **Files, commits and commit details from git.** `arb backfill-git-raw --raw raw --repo R --repos-dir git_raw_repos`, driven by `scripts/crawl_repo.sh R 250` (which also runs step 1). No REST. +3. **Diff-consistency filter** (`scripts/consistent_raw.py`, a deviation, see below): `raw` to `raw_consistent`. +4. **Mining with default filters.** `arb mine-code2test-prs --raw raw_consistent` and `arb mine-edit2ripple --raw raw_consistent` into `stage1/`. +5. **Preselection for corpus building** (`scripts/finalize.py --per-repo-limit 33` for code2test and `28` for edit2ripple, `--repo-share 1.0`) into `preselect/`. This only keeps corpus building bounded. +6. **Corpus.** `arb build-corpus preselect//samples.jsonl --repos-dir ../repos --out ../data/corpus/v2_ --no-keep-list`. Chunk files for commits shared by both tasks are hard-linked; ARB reuses existing chunk files through `existing_chunks_manifest`. +7. **Re-mining with ARB's corpus gates.** `arb mine-code2test-prs|mine-edit2ripple --raw raw_consistent --corpus-manifest data/corpus/v2_/corpus_manifest.jsonl --require-corpus --require-gold-in-corpus` into `stage2/`. +8. **Final selection** (`scripts/finalize.py --task --samples stage2//samples.jsonl --out data/benchmark/v2_ --per-repo-limit 25|20`). In order: ARB's fatal-leakage filter, a recency-ordered per-repo limit, the edit2ripple test-only quota, the 25% per-repo cap. +9. **Final corpus.** `build-corpus` re-run on the final samples to rewrite `corpus_manifest.jsonl`; chunk files no manifest references are deleted. +10. **Baselines**, as in "Running CGraph and scoring". + +## Filter funnel + +| repo | GraphQL PRs seen | kept (merged, <=20 files) | git-backfilled | diff-consistent | +|---|---:|---:|---:|---:| +| prometheus/prometheus | 252 | 250 | 250 | 200 | +| labstack/echo | 253 | 250 | 250 | 237 | +| spf13/cobra | 253 | 250 | 250 | 231 | +| sharkdp/bat | 251 | 250 | 249 | 248 | +| psf/black | 250 | 250 | 250 | 231 | +| Textualize/rich | 253 | 250 | 250 | 239 | +| honojs/hono | 257 | 250 | 250 | 193 | +| colinhacks/zod | 260 | 250 | 250 | 199 | +| nushell/nushell | 262 | 250 | 249 | 166 | +| tokio-rs/axum | 256 | 250 | 250 | 242 | + +Two PRs are missing from the git-backfilled column: + +- **bat:** one PR came back as `no_changed_files`. +- **nushell:** `backfill-git-raw` crashed on PR #18261 with a `UnicodeDecodeError`. ARB's `run_process` calls `subprocess.run(..., text=True ...)` (git_raw.py:311), and that PR's diff contains a byte (0xff) that is not valid UTF-8. It crashed twice. It was the last PR processed, so 249 records had already been written. + +Every diff-consistency drop was `base_not_ancestor_of_head` (reported in `consistency_summary.json` by `consistent_raw.py`). + +Miner drop reasons, summed over all repos: + +- **code2test:** missing_impl_or_existing_tests 862, low_value_pr 637, test_path_leak 114, weak_query 54, too_many_tests 38, query_noise 1. +- **edit2ripple:** changed_file_limit 807, no_related_gold_or_query_leakage 310, missing_anchor 228, low_value_pr 227, rename_or_generated_only 2. + +The corpus-gated re-mine also dropped `gold_missing_from_corpus` rows: 2 per task. + +**code2test** + +| repo | miner (no corpus) | preselected for corpus | miner with corpus gates | after ARB fatal-leakage filter | final | +|---|---:|---:|---:|---:|---:| +| prometheus/prometheus | 64 | 33 | 31 | 31 | 25 | +| labstack/echo | 66 | 33 | 33 | 33 | 25 | +| spf13/cobra | 30 | 30 | 30 | 30 | 25 | +| sharkdp/bat | 32 | 32 | 32 | 32 | 25 | +| psf/black | 32 | 32 | 32 | 32 | 25 | +| Textualize/rich | 80 | 33 | 33 | 33 | 25 | +| honojs/hono | 73 | 33 | 34 | 34 | 25 | +| colinhacks/zod | 73 | 33 | 34 | 34 | 25 | +| nushell/nushell | 26 | 26 | 26 | 26 | 25 | +| tokio-rs/axum | 4 | 4 | 4 | 4 | 4 | +| **total** | 480 | 289 | 289 | 289 | 229 | + +**edit2ripple** + +| repo | miner (no corpus) | preselected for corpus | miner with corpus gates | after ARB fatal-leakage filter | final | +|---|---:|---:|---:|---:|---:| +| prometheus/prometheus | 89 | 28 | 28 | 28 | 20 | +| labstack/echo | 110 | 28 | 28 | 28 | 17 | +| spf13/cobra | 66 | 28 | 31 | 31 | 20 | +| sharkdp/bat | 34 | 28 | 28 | 28 | 18 | +| psf/black | 77 | 28 | 29 | 29 | 20 | +| Textualize/rich | 115 | 28 | 28 | 28 | 19 | +| honojs/hono | 95 | 28 | 28 | 28 | 13 | +| colinhacks/zod | 111 | 28 | 28 | 28 | 20 | +| nushell/nushell | 64 | 28 | 28 | 28 | 20 | +| tokio-rs/axum | 50 | 28 | 28 | 28 | 20 | +| **total** | 811 | 280 | 284 | 284 | 187 | + +- **Gated count above preselected:** the corpus-gated re-mine can return more rows than were preselected. Any extra row reuses a base commit whose corpus was already built. +- **Final edit2ripple below 20:** some repos end with fewer than 20 rows because their 28-row pool did not hold enough rows under the test-only quota. +- **Largest repo share:** 25 of 229 (10.9%) for code2test and 20 of 187 (10.7%) for edit2ripple, well under the 25% cap. + +## Audit substitute (no human audit) + +1. **ARB's mechanical miner filters at their CLI defaults.** code2test: `--max-changed-files 20` and `--max-tests 3` (cli.py:290-291), plus `missing_impl_or_existing_tests`, `too_many_tests`, `query_noise` and `test_path_leak` (code2test_pr.py:200, 202, 209, 211). edit2ripple: `--max-changed-files 8` and `--max-candidates-per-pr 2` (cli.py:305, 307); candidates with fatal leakage are discarded (`if leakage["fatal"]:`, edit2ripple.py:694). +2. **ARB's corpus gates:** `--require-corpus --require-gold-in-corpus`. Every gold file exists in its commit's corpus; re-verified after final selection: 0 missing. +3. **ARB's leakage filters.** A row is dropped if `dataset_validity.detect_query_leakage(row)["fatal"]` (fatal types `{"exact_gold_path", "raw_patch_marker", "review_leakage", "fix_commit_hash"}`, dataset_validity.py:34) or `baseline.query_has_leakage` (baseline.py:517, the check `eval-baseline` uses to skip a sample) is true. Result: 0 drops in both tasks, because the miners' own gates had already removed these rows. The same detector reports 0 fatal leaks on the released gin/caddy/clap rows. +4. **edit2ripple test-only policy.** At most `floor(0.25 x 20) = 5` test-only-gold rows per repo, following the released `strict25_policy` (`"max_test_only_ratio": 0.25`, `data/reports/v2_edit2ripple/edit2ripple_strict_expanded_v1/selection_summary.json:39`). The final test-only share is 0.235. `report-edit2ripple-pilot` defaults to the looser `max_test_only_ratio: float = 0.35` (edit2ripple.py:506). +5. **Lexical hardness pass (`hard-pool-filter` / `too_easy_lexical`): not applied.** The released v2 rows show no evidence of it: + - None of the 17 PR-mined code2test dev rows carries hardness metadata. Their metadata keys are only `confidence, created_at, evidence, generated_at, merged_at, pr, pr_url`. The other 2 rows carry `hardmine_source` from the older derive path. + - The released rows still contain samples that rule would have removed. hardness.py:293-296 labels a row `too_easy_lexical` when it is not hard and lexical `Recall@5 >= 1.0`. In the released lexical baseline details for the dev repos, 12 of 28 edit2ripple rows and 1 of 19 code2test rows meet that rule (R@5 = 1, R@20 = 1, MRR >= 0.25), and they were released anyway. +6. **Audit block.** edit2ripple rows keep the miner's audit block with `"verdict": "pending"` plus a note saying no human audit was done. Released rows say `"valid"` because they were audited; extdev does not claim that. + +## Deviations from ARB's pipeline, and why + +- **GraphQL-only metadata driver instead of `arb crawl --no-checks`.** It writes identical `pull_request` records but skips crawl's 3+N REST calls per PR, to keep API cost low. `backfill-git-raw` then fills files, commits and commit details from git. +- **Diff-consistency filter after `backfill-git-raw`.** ARB's backfill diffs `base..head` two-dot (`git diff --name-status --find-renames base head`, git_raw.py:203). GitHub's PR file list is the merge-base diff, so the two agree only when `baseRefOid` is an ancestor of `headRefOid`. In the hono pilot, PR #5233 had GraphQL `changedFiles=2`, but the git diff listed 311 files. Across the 40 pilot PRs, the ancestor test and an equal file count agreed on every one: all 10 inconsistent PRs failed the ancestor test. + - The rule: keep a PR only if base is an ancestor of head and the git file count equals `changedFiles`. This removed between 0.8% (bat) and 34% (nushell) of PRs per repo, counting PRs the backfill did not produce; hono, zod and prometheus also lost 20% or more. The filter is biased against long-lived branches. + - It is conservative: `fetch --depth 50` (git_raw.py:192) can hide ancestry, which can only cause a wrong drop, never a wrong keep. +- **Fixed per-repo limit (25 for code2test, 20 for edit2ripple) and recency ordering.** The raw yield was 480 code2test and 811 edit2ripple candidates. Equal per-repo limits keep the corpus and the CGraph run size reasonable and stay far below the 25% cap. + - Rows are chosen by PR number descending, the order the miners walk PRs. An earlier pass used the miners' audit-priority `sample_sort_key`, which favors multi-file non-test gold. It produced an edit2ripple set with only 2% test-only gold and 2.71 gold files per sample, against the released dev rows' 43% and 1.54. Recency ordering gives the figures below. + + | statistic | released dev rows (gin/caddy/clap) | extdev | + |---|---:|---:| + | edit2ripple gold files per sample | 1.54 | 2.01 | + | edit2ripple test-only gold | 42.9% | 23.5% | + | edit2ripple changed files | 3.5 | 4.34 | + | code2test tests per sample | 1.21 | 1.28 | + | code2test implementation files | 1.89 | 2.02 | + +- **Two-pass mining.** Mining runs once without the corpus, then again with the corpus gates after corpora are built only for a preselected superset. Building corpora for all 1,291 candidates was unnecessary. +- **Schema.** code2test rows add top-level `query_provenance: "pr_summary"`, which matches the released rows and `baseline.query_provenance`'s code2test default. Remaining gaps against the released gin/caddy/clap rows: + - **code2test, `gold_blocks` / `gold_spans`:** from manual span annotations; they feed span and block metrics only, not R@k, MRR or BCY. ARB has no deterministic way to produce them. + - **code2test, `hard_negative_files`:** present on 1 of 19 released rows. + - **code2test, `query.changed_file` and `metadata.hardmine_source`:** only on the 2 released rows from the older derive path. + - **edit2ripple, `metadata.source`, `source_samples`, `expansion_candidate_sources` and `improvement`:** provenance of the from-sample-commits and expansion paths, which do not apply to the raw-PR miner. + + All other keys match. +- **Manifests.** `manifest.json` files use `schema: "arb_extdev_v2"` and record the funnel and selection parameters. + +## Baseline scores on extdev (ARB harness, all_files candidates, scored with `score.py --tasks code2test edit2ripple`) + +| Method | Task | n | R@20 | MRR | BCY@8k | +|---|---|---:|---:|---:|---:| +| RepoMap | code2test | 229 | 0.8530 | 0.4980 | 0.6783 | +| Lexical | code2test | 229 | 0.7285 | 0.2058 | 0.4047 | +| BM25 | code2test | 229 | 0.6667 | 0.2516 | 0.3588 | +| RepoMap | edit2ripple | 187 | 0.7571 | 0.4008 | 0.4630 | +| Lexical | edit2ripple | 187 | 0.7086 | 0.2874 | 0.4661 | +| BM25 | edit2ripple | 187 | 0.5945 | 0.2842 | 0.3592 | +| RepoMap | overall | 416 | 0.8099 | 0.4543 | 0.5815 | +| Lexical | overall | 416 | 0.7196 | 0.2424 | 0.4323 | +| BM25 | overall | 416 | 0.6342 | 0.2663 | 0.3590 | + +`score.py` also prints R@5/10, BCY@4k-32k and the given-file-excluded diagnostic. Every baseline summary reports `skipped: {}`, so all 229 and 187 samples were evaluated. + +For reference only, the released dev split (gin/caddy/clap) scores as follows with the same baselines (R@20 / MRR): + +| Method | code2test (n=19) | edit2ripple (n=28) | +|---|---:|---:| +| RepoMap | 0.947 / 0.360 | 0.768 / 0.312 | +| Lexical | 0.316 / 0.064 | 0.673 / 0.297 | +| BM25 | 0.316 / 0.137 | 0.750 / 0.220 | + +On extdev, edit2ripple scores are close to the released dev split. code2test is noticeably easier for Lexical and BM25 on extdev. diff --git a/bench/arb/extdev/data/benchmark/v2_code2test/manifest.json b/bench/arb/extdev/data/benchmark/v2_code2test/manifest.json new file mode 100644 index 0000000..a04eae0 --- /dev/null +++ b/bench/arb/extdev/data/benchmark/v2_code2test/manifest.json @@ -0,0 +1,85 @@ +{ + "audit": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", + "funnel": { + "after_arb_leakage_filter": { + "Textualize/rich": 33, + "colinhacks/zod": 34, + "honojs/hono": 34, + "labstack/echo": 33, + "nushell/nushell": 26, + "prometheus/prometheus": 31, + "psf/black": 32, + "sharkdp/bat": 32, + "spf13/cobra": 30, + "tokio-rs/axum": 4 + }, + "after_per_repo_limit_25": { + "Textualize/rich": 25, + "colinhacks/zod": 25, + "honojs/hono": 25, + "labstack/echo": 25, + "nushell/nushell": 25, + "prometheus/prometheus": 25, + "psf/black": 25, + "sharkdp/bat": 25, + "spf13/cobra": 25, + "tokio-rs/axum": 4 + }, + "after_test_only_policy_and_repo_cap": { + "Textualize/rich": 25, + "colinhacks/zod": 25, + "honojs/hono": 25, + "labstack/echo": 25, + "nushell/nushell": 25, + "prometheus/prometheus": 25, + "psf/black": 25, + "sharkdp/bat": 25, + "spf13/cobra": 25, + "tokio-rs/axum": 4 + }, + "mined_with_corpus_gates": { + "Textualize/rich": 33, + "colinhacks/zod": 34, + "honojs/hono": 34, + "labstack/echo": 33, + "nushell/nushell": 26, + "prometheus/prometheus": 31, + "psf/black": 32, + "sharkdp/bat": 32, + "spf13/cobra": 30, + "tokio-rs/axum": 4 + } + }, + "name": "v2_code2test", + "paths": { + "benchmark": "data/benchmark/v2_code2test", + "corpus": "data/corpus/v2_code2test" + }, + "repo_counts": { + "Textualize/rich": 25, + "colinhacks/zod": 25, + "honojs/hono": 25, + "labstack/echo": 25, + "nushell/nushell": 25, + "prometheus/prometheus": 25, + "psf/black": 25, + "sharkdp/bat": 25, + "spf13/cobra": 25, + "tokio-rs/axum": 4 + }, + "sample_count": 229, + "schema": "arb_extdev_v2", + "selection": { + "fatal_leakage_dropped_by_type": {}, + "order": "recency", + "per_repo_limit": 25, + "repo_cap": 25, + "repo_share": 0.25, + "test_only_dropped": 0, + "test_only_ratio": null + }, + "task_counts": { + "code2test": 229 + }, + "task_type": "code2test" +} diff --git a/bench/arb/extdev/data/benchmark/v2_code2test/samples.jsonl b/bench/arb/extdev/data/benchmark/v2_code2test/samples.jsonl new file mode 100644 index 0000000..c12e7ec --- /dev/null +++ b/bench/arb/extdev/data/benchmark/v2_code2test/samples.jsonl @@ -0,0 +1,229 @@ +{"base_commit": "6e69e843b38d22ded60a13e0163f6326136f59fa", "candidate_corpus": {"base_commit": "6e69e843b38d22ded60a13e0163f6326136f59fa", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "7d9f8fa7bffb7216d241c0ed1783802351bb56a8", "negative_distractors": [], "related_tests": ["model/textparse/openmetrics2parse_test.go"], "root_cause_files": ["model/textparse/openmetrics2parse.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "847d8cd6fc4d593630e8cc3e", "metadata": {"confidence": "weak", "created_at": "2026-10-14T16:06:09Z", "evidence": {"implementation_files": ["model/textparse/openmetrics2parse.go"], "related_tests": ["model/textparse/openmetrics2parse_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-16T06:57:45Z", "pr": 20020, "pr_url": "https://github.com/prometheus/prometheus/pull/20020"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["model/textparse/openmetrics2parse.go"], "pr_body": "When expanding an OpenMetrics 2.0 composite histogram into classic series (`_count`/`_gcount`, `_sum`/`_gsum`, `_bucket`), attach each exemplar on the line to the `_bucket` series with the smallest `le` threshold greater than or equal to the exemplar value (falling back to `+Inf` for `NaN`), rather than returning all exemplars on the first pending series (`_count`).\n\nWhen both a native histogram (or NHCB via `ConvertClassicHistogramsToNHCB`) and classic histogram series (`KeepClassicOnClassicAndNativeHistograms`) are emitted for the same sample line, return the exemplars on both the `EntryHistogram` and the matching classic `_bucket` `EntrySeries`, matching `ProtobufParser`.\n\n#### Which issue(s) does the PR fix:\n\nFixes #19869\nPart of #19745\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n```release-notes\n[BUGFIX] OpenMetrics 2.0: Attach histogram exemplars to matching classic `_bucket` series and preserve them when scraping both native and classic histograms.\n```", "pr_title": "model/textparse: align OM 2.0 histogram exemplar parsing with protobuf"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "ad230dcfd02f0f93d7c31349766240cedea97f44", "candidate_corpus": {"base_commit": "ad230dcfd02f0f93d7c31349766240cedea97f44", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "26b3ee772d031a380b4a82072f444e7256889aff", "negative_distractors": [], "related_tests": ["storage/remote/otlptranslator/prometheusremotewrite/helper_test.go"], "root_cause_files": ["storage/remote/otlptranslator/prometheusremotewrite/helper.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "5131ab4461e61ae3a6cfcb74", "metadata": {"confidence": "weak", "created_at": "2026-10-13T12:51:48Z", "evidence": {"implementation_files": ["storage/remote/otlptranslator/prometheusremotewrite/helper.go"], "related_tests": ["storage/remote/otlptranslator/prometheusremotewrite/helper_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-16T08:06:42Z", "pr": 20004, "pr_url": "https://github.com/prometheus/prometheus/pull/20004"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["storage/remote/otlptranslator/prometheusremotewrite/helper.go"], "pr_body": "#### Which issue(s) does the PR fix:\n\nFollow-up to #19896.\n\n#### Description\n\nWhen an OTLP exemplar has a trace ID or span ID, the OTLP translator adds them as `trace_id` and `span_id` exemplar labels, then appends every filtered attribute unchanged. If a filtered attribute is itself named `trace_id` or `span_id`, the exemplar ends up with duplicate label names. Before #19896 such an exemplar was stored and served with a duplicate JSON key from `/api/v1/query_exemplars`. Since #19896, TSDB rejects it as invalid, so the whole exemplar is dropped.\n\nSuch input is valid OTLP: the trace context lives in dedicated fields, so it does not collide with the filtered attributes inside OTLP itself. The [OpenTelemetry Prometheus compatibility specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/compatibility/prometheus_and_openmetrics.md#exemplars-1) requires that the `trace_id` and `span_id` labels \"MUST take precedence over labels from `filtered_attributes` in cases where there is a key collision\".\n\nThis PR drops a filtered attribute only when it collides with a label that was actually set from the trace context. If only a trace ID is present, a `span_id` filtered attribute is kept, and vice versa. Dropped attributes also no longer count towards the exemplar rune limit, so they cannot cause the remaining filtered attributes to be discarded.\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n```release-notes\n[BUGFIX] OTLP: Do not drop exemplars that have a `trace_id` or `span_id` filtered attribute in addition to a trace or span ID. The trace context now takes precedence over the colliding attribute, as required by the OpenTelemetry specification.\n```\n\n🤖 Generated wi\n...[truncated]", "pr_title": "otlp: let exemplar trace context take precedence over filtered attributes"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "fd4847802c65256cb16e34f5e5c0e52a4b584cb6", "candidate_corpus": {"base_commit": "fd4847802c65256cb16e34f5e5c0e52a4b584cb6", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "2377dc1460206961d819ee3e2f6032b98a9e148c", "negative_distractors": [], "related_tests": ["promql/engine_test.go", "promql/promqltest/testdata/type_and_unit.test"], "root_cause_files": ["promql/engine.go", "promql/functions.go", "promql/info.go"], "root_cause_symbols": [], "supporting_files": ["docs/querying/operators.md"]}, "id": "19f3041e078d87d80b27cfb1", "metadata": {"confidence": "weak", "created_at": "2026-10-10T18:14:15Z", "evidence": {"implementation_files": ["promql/engine.go", "promql/functions.go", "promql/info.go"], "related_tests": ["promql/engine_test.go", "promql/promqltest/testdata/type_and_unit.test"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-12T16:05:18Z", "pr": 19986, "pr_url": "https://github.com/prometheus/prometheus/pull/19986"}, "query": {"changed_file_summary": "3 implementation files and 2 existing test files changed within 6 total files.", "implementation_file_count": 3, "implementation_files": ["promql/engine.go", "promql/functions.go", "promql/info.go"], "pr_body": "Follow-up to #16228 and #18680 to ensure `__type__` and `__unit__` metadata labels are consistently ignored and dropped wherever `__name__` is ignored or dropped in PromQL:\n\n* Ignore and drop `__type__` and `__unit__` in `without(...)` aggregations (`generateGroupingKey` / `generateGroupingLabels`).\n* Exclude `__type__` and `__unit__` in `VectorBinop` label matching helpers when `!matching.On` (used for `fill` / `fill_left` / `fill_right` synthetic samples and duplicate-series error messages).\n* Drop all metadata labels via `schema.IsMetadataLabel` in `simpleHistogramFunc` (when delayed name removal is disabled), `createLabelsForAbsentFunction` (`absent()` / `absent_over_time()`), and `combineWithInfoVector` (`info()`).\n* Update `docs/querying/operators.md` to note that `__type__` and `__unit__` are dropped alongside `__name__`.\n\n#### Which issue(s) does the PR fix:\nPart of #16610\nRelated to #18635, #18680\n\n#### Release notes for end users (**ALL** commits must be considered).\n\n```release-notes\n[BUGFIX] PromQL: Consistently ignore and drop `__type__` and `__unit__` labels in `without` aggregations, `absent()`, `info()`, and binary operator fill matching.\n```", "pr_title": "promql: ignore and drop __type__ and __unit__ consistently across operators and functions"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "cc0aa45f6292160cbd501d4cd55d589d70629aa2", "candidate_corpus": {"base_commit": "cc0aa45f6292160cbd501d4cd55d589d70629aa2", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "6e57ac2bac3b014f41eb3f77eb6e0adae4cf3d97", "negative_distractors": [], "related_tests": ["promql/quantile_test.go"], "root_cause_files": ["promql/quantile.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "c4292e0ed23e06d8a64c27b2", "metadata": {"confidence": "weak", "created_at": "2026-10-07T12:58:10Z", "evidence": {"implementation_files": ["promql/quantile.go"], "related_tests": ["promql/quantile_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-12T11:36:04Z", "pr": 19963, "pr_url": "https://github.com/prometheus/prometheus/pull/19963"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["promql/quantile.go"], "pr_body": "#### Which issue(s) does the PR fix:\n\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n\n```release-notes\nNONE\n```", "pr_title": "promql: simplify BucketFraction guard and tests"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "39c878f024238783f54631e3a5998e835d04db86", "candidate_corpus": {"base_commit": "39c878f024238783f54631e3a5998e835d04db86", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "cc0aa45f6292160cbd501d4cd55d589d70629aa2", "negative_distractors": [], "related_tests": ["promql/quantile_test.go"], "root_cause_files": ["promql/quantile.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "b0cd1589d52e961ac4d6b687", "metadata": {"confidence": "weak", "created_at": "2026-10-06T23:31:09Z", "evidence": {"implementation_files": ["promql/quantile.go"], "related_tests": ["promql/quantile_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-07T12:48:22Z", "pr": 19944, "pr_url": "https://github.com/prometheus/prometheus/pull/19944"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["promql/quantile.go"], "pr_body": "Fixes #19943\n\nThe exported `BucketFraction` helper panics with `index out of range [-1]` for a nil or empty bucket slice: it reads `buckets[len(buckets)-1]` to check for a `+Inf` last bucket before any length check. Return `NaN` for nil and empty slices, mirroring the `BucketQuantile` fix in #19927 (this is the follow-up @krajorama asked for there) and the native-histogram counterpart's zero-observation behavior. `NaN` is also what `BucketFraction` already returns for a nonempty slice whose last bucket is not `+Inf` and for a zero total count, so no new semantics are introduced.\n\nThis corrects an internal exported-helper contract; the current PromQL call site in `funcHistogramFraction` guards empty bucket lists before calling the helper, so no expression-evaluation failure is claimed.\n\nVerification:\n- The reporter's repro (`BucketFraction(0, 1, nil)`) panics on pristine `main` (39c878f) at `promql/quantile.go:544` and returns `NaN` with this change.\n- New `TestBucketFraction_EmptyBuckets` covers nil and non-nil empty slices across finite, reversed, infinite, and NaN bounds (all `NaN`), with a zero-count `+Inf` control; it panics with only the production change reverted and passes with it restored. A small `TestBucketFraction` control pins existing nonempty behavior (interpolated fraction, full range, reversed bounds).\n- Full `go test ./promql` passes; `gofmt` clean.\n\n```release-notes\nNONE\n```\n\nDeveloped with AI assistance.", "pr_title": "promql: handle empty input in BucketFraction"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "770ca8fb8f8e0765318910f2c43107261f9b875d", "candidate_corpus": {"base_commit": "770ca8fb8f8e0765318910f2c43107261f9b875d", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "39c878f024238783f54631e3a5998e835d04db86", "negative_distractors": [], "related_tests": ["promql/quantile_test.go"], "root_cause_files": ["promql/quantile.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "7abdaba29423d245406ccb84", "metadata": {"confidence": "weak", "created_at": "2026-10-06T03:52:13Z", "evidence": {"implementation_files": ["promql/quantile.go"], "related_tests": ["promql/quantile_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-06T12:10:17Z", "pr": 19927, "pr_url": "https://github.com/prometheus/prometheus/pull/19927"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["promql/quantile.go"], "pr_body": "The exported `BucketQuantile` helper documents `NaN` for fewer than two buckets, but an empty slice currently panics while reading its last element. Return `NaN` for nil and empty slices after processing special quantile values. Preserve the existing precedence for `NaN` and out-of-range quantiles, flags, and additional metadata. `BucketFraction` is outside this change.\n\nThis corrects an internal exported-helper contract; current PromQL call sites guard empty bucket inputs, so no expression-evaluation failure is claimed. The ordinary regression covers nil and non-nil empty slices at `q=0`, `0.5`, and `1`, plus `NaN`, below-zero, and above-one controls. It panics with only the production repair removed and passes with it restored. Relevant existing bucket tests and PromQL package lint pass.\n\n```release-notes\nNONE\n```\n\nDeveloped with AI assistance; the broader property-testing machinery is maintained separately.", "pr_title": "promql: handle empty input in BucketQuantile"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "770ca8fb8f8e0765318910f2c43107261f9b875d", "candidate_corpus": {"base_commit": "770ca8fb8f8e0765318910f2c43107261f9b875d", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "97541926b9e99ce298c285e67e71ebf993e9f2ff", "negative_distractors": [], "related_tests": ["model/histogram/float_histogram_test.go"], "root_cause_files": ["model/histogram/float_histogram.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "d74501d46f278c3709560859", "metadata": {"confidence": "weak", "created_at": "2026-10-06T03:42:17Z", "evidence": {"implementation_files": ["model/histogram/float_histogram.go"], "related_tests": ["model/histogram/float_histogram_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-07T05:44:16Z", "pr": 19916, "pr_url": "https://github.com/prometheus/prometheus/pull/19916"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["model/histogram/float_histogram.go"], "pr_body": "`FloatHistogram.CopyToSchema` changed `CounterReset`, `NotCounterReset`, and `GaugeType` to `UnknownCounterReset` when reducing an exponential histogram's schema. Preserve the reset hint in the returned copy, consistent with `Copy` and the equal-schema path. The table-driven regression covers every reset hint, schema reduction, unchanged schemas, and custom layouts.\n\nThe unchanged regression fails without the production repair; fresh tests for the complete `model/histogram` package pass with it.\n\n```release-notes\nNONE\n```\n\nDeveloped with AI assistance; the broader property-testing machinery is maintained separately.", "pr_title": "model/histogram: preserve counter reset hints in CopyToSchema"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "770ca8fb8f8e0765318910f2c43107261f9b875d", "candidate_corpus": {"base_commit": "770ca8fb8f8e0765318910f2c43107261f9b875d", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "92ac7f79130ef5c79f2c80e2164fce8ecb7de183", "negative_distractors": [], "related_tests": ["tsdb/head_test.go", "tsdb/index/index_test.go"], "root_cause_files": ["tsdb/head_read.go", "tsdb/index/index.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "b0d56639dfacd0e3c2207638", "metadata": {"confidence": "weak", "created_at": "2026-10-06T00:01:31Z", "evidence": {"implementation_files": ["tsdb/head_read.go", "tsdb/index/index.go"], "related_tests": ["tsdb/head_test.go", "tsdb/index/index_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-13T11:35:42Z", "pr": 19915, "pr_url": "https://github.com/prometheus/prometheus/pull/19915"}, "query": {"changed_file_summary": "2 implementation files and 2 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["tsdb/head_read.go", "tsdb/index/index.go"], "pr_body": "Preserve input postings errors in head and block `ShardedPostings`.\nFailed inputs currently become list postings with a nil error.\n\nThis affects TSDB library callers using query sharding. Prometheus does not set `ShardCount`.\nTests cover empty and non-empty failing inputs.\n\nValidation:\n- `go test ./tsdb/... -count=1`\n- Sharded postings tests with `-race -count=5`.\n- `go build ./cmd/prometheus`\n- `make lint`\n\ncc @bboreham \n\n#### Which issue(s) does the PR fix:\nNone.\n\n#### Release notes for end users\n```release-notes\nNONE\n```", "pr_title": "tsdb: return error from ShardedPostings if input errors"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "d4467eede8e6d171c7ee06c0307a34878339a237", "candidate_corpus": {"base_commit": "d4467eede8e6d171c7ee06c0307a34878339a237", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "21fd457f2b67fe417e181817d814dba812471e9f", "negative_distractors": [], "related_tests": ["cmd/promtool/rules_test.go"], "root_cause_files": ["cmd/promtool/analyze.go", "cmd/promtool/query.go", "cmd/promtool/rules.go"], "root_cause_symbols": [], "supporting_files": ["go.mod", "go.sum"]}, "id": "5a115369e701b6ac68e27723", "metadata": {"confidence": "weak", "created_at": "2026-10-05T16:39:12Z", "evidence": {"implementation_files": ["cmd/promtool/analyze.go", "cmd/promtool/query.go", "cmd/promtool/rules.go"], "related_tests": ["cmd/promtool/rules_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-08T14:17:11Z", "pr": 19913, "pr_url": "https://github.com/prometheus/prometheus/pull/19913"}, "query": {"changed_file_summary": "3 implementation files and 1 existing test files changed within 6 total files.", "implementation_file_count": 3, "implementation_files": ["cmd/promtool/analyze.go", "cmd/promtool/query.go", "cmd/promtool/rules.go"], "pr_body": "Tests v1.25.0 (final) of client_golang. The RC was validated in https://github.com/prometheus/prometheus/pull/19913/ with no issues found; this bumps the tree to the released tag.\n\n## Known effects (as I had to change promtool):\n* `client_golang`'s `Query`, `QueryRange`, `Series`, `LabelNames`, and `LabelValues` now return `Infos` annotations in addition to `Warnings` (client_golang#1963). `promtool` ignores infos for query commands (same as warnings); the rule importer logs them.\n* Minimum Go version required by `client_golang` is now 1.26 (client_golang#2138).\n\nAlso bumps `prometheus/common` to v0.72.0, `procfs` to v0.22.0 (transitive requirements of `client_golang` v1.25.0), and the `exp` module to the release commit.\n\n```release-notes\nNONE\n```", "pr_title": "Upgrade client_golang to 1.25.0"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "961c9ba40923ca4d7adf4a7a9167e56d0406df83", "candidate_corpus": {"base_commit": "961c9ba40923ca4d7adf4a7a9167e56d0406df83", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "b2c301420f56e1498bec668b5bb9af7dc45773bf", "negative_distractors": [], "related_tests": ["scrape/scrape_test.go", "web/api/v1/search_test.go"], "root_cause_files": ["web/api/v1/search.go"], "root_cause_symbols": [], "supporting_files": ["docs/querying/api.md"]}, "id": "85af7e59f1b620de18bcbb44", "metadata": {"confidence": "weak", "created_at": "2026-10-05T02:24:48Z", "evidence": {"implementation_files": ["web/api/v1/search.go"], "related_tests": ["scrape/scrape_test.go", "web/api/v1/search_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-05T09:07:15Z", "pr": 19910, "pr_url": "https://github.com/prometheus/prometheus/pull/19910"}, "query": {"changed_file_summary": "1 implementation files and 2 existing test files changed within 4 total files.", "implementation_file_count": 1, "implementation_files": ["web/api/v1/search.go"], "pr_body": "#### Which issue(s) does the PR fix:\n\nThis PR is a follow up to https://github.com/prometheus/prometheus/pull/19824 and fixes an issue where metrics with double `_total` or `_info` suffixes are incorrectly considered as part of the wrong series family.\n\nThis can result in incorrect metadata added to metrics via the experimental search API.\n\nPrior to this PR `metadataForMetric` strips the last suffix and matches it against the family name. So `requests_total_total` gets the metadata of a `requests_total` counter, and `build_info_info` gets the metadata of a `build_info` info metric.\n\nThis is inconsistent with how `isSeriesPartOfFamily` in `scrape/scrape.go` would treat the same metric name, which would not consider `requests_total_total` part of the `requests_total` family.\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n```release-notes\n[BUGFIX] API: Do not match metric family metadata for doubled _total and _info suffixes in experimental search API.\n```", "pr_title": "web/api/v1: Fix for metadata enrichment on double suffixed _total and _info"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "961c9ba40923ca4d7adf4a7a9167e56d0406df83", "candidate_corpus": {"base_commit": "961c9ba40923ca4d7adf4a7a9167e56d0406df83", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "d4467eede8e6d171c7ee06c0307a34878339a237", "negative_distractors": [], "related_tests": ["template/template_test.go"], "root_cause_files": ["template/template.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "12a5cd07209d7ffe8bdb0adc", "metadata": {"confidence": "weak", "created_at": "2026-10-04T06:57:51Z", "evidence": {"implementation_files": ["template/template.go"], "related_tests": ["template/template_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-07T16:11:04Z", "pr": 19908, "pr_url": "https://github.com/prometheus/prometheus/pull/19908"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["template/template.go"], "pr_body": "## Problem\n\n`stripDomain` used `net.ParseIP` to detect IP literals. `net.ParseIP` rejects any address containing a zone identifier (`%…`), so such inputs fell through to the hostname path and were truncated at the first `.` inside the zone:\n\nCloses #19897\n\n| Input | Before | After |\n| --- | --- | --- |\n| `fe80::1%eth0.100` | `fe80::1%eth0` | `fe80::1%eth0.100` |\n| `[fe80::1%eth0.100]:9090` | `[fe80::1%eth0]:9090` | `[fe80::1%eth0.100]:9090` |\n| `::ffff:192.0.2.1%eth0.100` | `::ffff:192` | `::ffff:192.0.2.1%eth0.100` |\n\n## Fix\n\nReplace the `net.ParseIP` check with `netip.ParseAddr`, which accepts zone identifiers. Hostname handling and plain IPv4/IPv6 literals are unchanged.\n\n```release-notes\n[BUGFIX] Templates: Preserve IPv6 addresses with dotted zone identifiers in `stripDomain`.\n```", "pr_title": "template: stripDomain truncates IPv6 zone identifiers containing dots"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "961c9ba40923ca4d7adf4a7a9167e56d0406df83", "candidate_corpus": {"base_commit": "961c9ba40923ca4d7adf4a7a9167e56d0406df83", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "9aee60fd0d7f19b8786f05e279feabd00dca5fcd", "negative_distractors": [], "related_tests": ["scrape/scrape_test.go"], "root_cause_files": ["scrape/scrape.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "1c9416dca97499932a3bf10d", "metadata": {"confidence": "weak", "created_at": "2026-10-03T14:39:50Z", "evidence": {"implementation_files": ["scrape/scrape.go"], "related_tests": ["scrape/scrape_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-16T12:25:09Z", "pr": 19902, "pr_url": "https://github.com/prometheus/prometheus/pull/19902"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["scrape/scrape.go"], "pr_body": "acceptHeader only added the escaping parameter for PrometheusText 1.0.0 and OpenMetricsText 1.0.0. OpenMetrics 2.0 supports UTF-8 names natively, but client libraries (client_golang, client_java) fall back to their default escaping scheme (underscores) when the parameter is missing, so a UTF-8 metric like \"http.server.active_requests\" was stored as http_server_active_requests when scraped with OpenMetricsText2.0.0, unlike with OpenMetricsText1.0.0.\n\nSend the configured metric_name_escaping_scheme for OpenMetrics 2.0 too.\n\n\n\n#### Which issue(s) does the PR fix:\n\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n\n```release-notes\n[BUGFIX] textparse: Ensure UTF-8 works with the experimental OpenMetrics 2.0\n```", "pr_title": "scrape: request escaping scheme for OpenMetrics 2.0 scrapes"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "5ba0e8648a4314e7d12adc6dbeb34b9d76cafab2", "candidate_corpus": {"base_commit": "5ba0e8648a4314e7d12adc6dbeb34b9d76cafab2", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "025b78f5eb995b742b7090ad8b192b07b60938c4", "negative_distractors": [], "related_tests": ["promql/promqltest/testdata/trig_functions.test"], "root_cause_files": ["promql/functions.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "18511cc70d0b98f1cd379a1e", "metadata": {"confidence": "weak", "created_at": "2026-10-03T12:37:35Z", "evidence": {"implementation_files": ["promql/functions.go"], "related_tests": ["promql/promqltest/testdata/trig_functions.test"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-13T11:39:19Z", "pr": 19901, "pr_url": "https://github.com/prometheus/prometheus/pull/19901"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["promql/functions.go"], "pr_body": "**What**\n- Avoid intermediate overflow in `rad()` and `deg()` for large inputs.\n\n**Why**\n- Current arithmetic can overflow before division even when the converted result is finite.\n\n**Implementation**\n- Apply the conversion factor before multiplying by the input.\n- Add regression coverage for large inputs to both functions.\n\n#### Which issue(s) does the PR fix:\n\nNone.\n\n#### Release notes for end users (**ALL** commits must be considered).\n\n```release-notes\n[BUGFIX] PromQL: Avoid intermediate overflow in `rad()` and `deg()` conversions.\n```", "pr_title": "promql: avoid overflow in rad and deg"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "5ba0e8648a4314e7d12adc6dbeb34b9d76cafab2", "candidate_corpus": {"base_commit": "5ba0e8648a4314e7d12adc6dbeb34b9d76cafab2", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "6036882468febf589e31134b3fab9889d4146603", "negative_distractors": [], "related_tests": ["promql/promqltest/testdata/aggregators.test", "promql/promqltest/testdata/functions.test"], "root_cause_files": ["promql/quantile.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "5426788d6d9d6d9e36dc3b4f", "metadata": {"confidence": "weak", "created_at": "2026-10-03T12:14:10Z", "evidence": {"implementation_files": ["promql/quantile.go"], "related_tests": ["promql/promqltest/testdata/aggregators.test", "promql/promqltest/testdata/functions.test"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-13T16:22:02Z", "pr": 19899, "pr_url": "https://github.com/prometheus/prometheus/pull/19899"}, "query": {"changed_file_summary": "1 implementation files and 2 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["promql/quantile.go"], "pr_body": "**What**\n- Preserve exact-rank quantile values when adjacent samples contain infinities.\n\n**Why**\n- Interpolation can evaluate `Inf * 0` at exact ranks and return `NaN`.\n\n**Implementation**\n- Return the selected sample when the interpolation weight is zero.\n- Add focused regression coverage for exact ranks with `+Inf` and `-Inf`.\n\n#### Which issue(s) does the PR fix:\n\nNone.\n\n#### Release notes for end users (**ALL** commits must be considered).\n\n```release-notes\n[BUGFIX] PromQL: Preserve infinite values at exact quantile ranks.\n```", "pr_title": "promql: preserve infinite values at exact quantile ranks"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "961c9ba40923ca4d7adf4a7a9167e56d0406df83", "candidate_corpus": {"base_commit": "961c9ba40923ca4d7adf4a7a9167e56d0406df83", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "6d833873a7aad133d822e952235b7549cafc8719", "negative_distractors": [], "related_tests": ["model/textparse/openmetrics2parse_test.go"], "root_cause_files": ["model/labels/float.go", "model/textparse/openmetrics2parse.go"], "root_cause_symbols": [], "supporting_files": ["model/labels/float_test.go"]}, "id": "1bc0d6d3c6fccf0c619ef5de", "metadata": {"confidence": "weak", "created_at": "2026-10-02T15:29:33Z", "evidence": {"implementation_files": ["model/labels/float.go", "model/textparse/openmetrics2parse.go"], "related_tests": ["model/textparse/openmetrics2parse_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-13T10:09:05Z", "pr": 19895, "pr_url": "https://github.com/prometheus/prometheus/pull/19895"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["model/labels/float.go", "model/textparse/openmetrics2parse.go"], "pr_body": "Optimize `openMetrics2Parser` CPU time and heap allocations across warm and cold scrape series caches:\n\n- Format exploded classic histogram (`_count`, `_sum`, `_bucket`) and summary (`_count`, `_sum`, quantile) series identity bytes directly into `p.seriesBuf` from `p.l.b` and `p.offsets` during `Next()`, and defer `labels.Labels` construction to `Labels()` so warm-cache scrapes do not sort or allocate `labels.Labels` on the heap.\n- Record exemplar label byte offsets into `p.eOffsets` during `Next()` and construct `e.Labels` lazily in `Exemplar()`.\n- Enable `SetUnsafeAdd(true)` on `p.builder` (matching `NewProtobufParser`) and pass `yoloString` slices in `Labels()` and `Exemplar()` to avoid intermediate string allocations before interning/cloning.\n- Return `&p.ts` from `Series()` and `Histogram()` instead of allocating a new `int64` on the heap per timestamped sample.\n- Skip redundant quote stripping and `utf8.Valid` checks on unquoted `tLName`/`tMName` tokens (already validated as non-empty ASCII by the lexer) and avoid redundant slice/pointer stores per sample.\n\n```\ngo test -count=6 -cpu=2 -benchmem -run='^$' -bench='^BenchmarkParseOM1VsOM2' ./model/textparse\n```\n\n```\ngoos: linux\ngoarch: amd64\npkg: github.com/prometheus/prometheus/model/textparse\ncpu: Intel(R) Xeon(R) CPU @ 2.20GHz\n │ before │ after │\n │ sec/op │ sec/op vs base │\nParseOM1VsOM2_AllTypes/parser=omtext-2 879.3µ ± 9% 856.2µ ± 1% ~ (p=0.589 n=6)\nParseOM1VsOM2_AllTypes/parser=omtext_with_nhcb-2 266.7µ ± 1% 269.9µ ± 2% ~ (p=0.093 n=6)\nParseOM1VsOM2_AllTypes/parser=om2text-2 123.2µ ± 1% 111.\n...[truncated]", "pr_title": "textparse [PERF]: defer OM2 composite and exemplar label allocations"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "fadf780dec7522178d84bcbb9ab6a78a82017a03", "candidate_corpus": {"base_commit": "fadf780dec7522178d84bcbb9ab6a78a82017a03", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "770ca8fb8f8e0765318910f2c43107261f9b875d", "negative_distractors": [], "related_tests": ["rules/manager_test.go"], "root_cause_files": ["rules/group.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "8c21072bdb8f9c9f8082f722", "metadata": {"confidence": "weak", "created_at": "2026-10-01T15:42:06Z", "evidence": {"implementation_files": ["rules/group.go"], "related_tests": ["rules/manager_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-05T10:20:20Z", "pr": 19882, "pr_url": "https://github.com/prometheus/prometheus/pull/19882"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["rules/group.go"], "pr_body": "#### Which issue(s) does the PR fix:\n\nFixes #15175\n\n#### Summary\n\nRules whose `for` duration is shorter than `--rules.alert.for-grace-period` currently skip restoration even when their persisted state was firing. Apply that skip only to pending alerts, so previously firing alerts recover `ActiveAt` and resume firing on the next scheduled evaluation.\n\nPending hold times, outage tolerance, and grace handling remain unchanged. `FiredAt` is set by normal evaluation rather than reconstructed from incomplete persisted state.\n\nThe regression table exercises firing durations below, equal to, and above the grace period; short pending holds; pending outage/grace behavior; an expired outage tolerance; and zero-duration rules. It performs the two startup evaluations before restoration and uses irregular pre-outage evaluations to distinguish the actual firing time from `ActiveAt + for`.\n\n#### Verification\n\n- Reproduced regression failures against the original implementation and the earlier PR revision.\n- `go test ./rules -run '^TestForStateRestore(HoldDuration)?$' -count=1`\n- `go test ./rules -count=1`\n- `go test -race ./rules -run '^TestForStateRestore(HoldDuration)?$' -count=1`\n- `go vet ./rules/...`\n- `make lint`\n- Prometheus application build and gofmt check\n- `git diff --check`\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n```release-notes\n[BUGFIX] Rules: Restore firing alerts with for durations shorter than --rules.alert.for-grace-period after a restart.\n```", "pr_title": "rules: restore firing alerts with short for durations"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "23b9aebefe8f295fe49c5be978c94bedfb7db70c", "candidate_corpus": {"base_commit": "23b9aebefe8f295fe49c5be978c94bedfb7db70c", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "d2266dcd4f690a20ed050ab0059d4de68ffa274a", "negative_distractors": [], "related_tests": ["promql/engine_test.go"], "root_cause_files": ["promql/engine.go", "util/stats/query_stats.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "2e3af0203ea1f78cfca0086b", "metadata": {"confidence": "weak", "created_at": "2026-09-30T09:01:25Z", "evidence": {"implementation_files": ["promql/engine.go", "util/stats/query_stats.go"], "related_tests": ["promql/engine_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-15T08:49:16Z", "pr": 19873, "pr_url": "https://github.com/prometheus/prometheus/pull/19873"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 2, "implementation_files": ["promql/engine.go", "util/stats/query_stats.go"], "pr_body": "TotalSamples measures logical underlying sample consumption. Subqueries\nalready merge that consumption into the parent statistics, so counting\ntheir materialized output in the outer range-vector function mixes\nunderlying consumption with intermediate processing. Exclude those points,\nconsistent with gathering intermediate vectors without charging them again\nto TotalSamples.\n\n\n\n#### Which issue(s) does the PR fix:\n\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n\n```release-notes\n[BUGFIX] PromQL: do not count subquery materialized samples in total samples statistics\n```", "pr_title": "promql: do not count subquery materialized samples in total samples"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "063606dbcfdf580f80449bb998d717b74a554388", "candidate_corpus": {"base_commit": "063606dbcfdf580f80449bb998d717b74a554388", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "6733617c8b5b541fe15d5f8d904928f8ff1d9d58", "negative_distractors": [], "related_tests": ["tsdb/head_test.go"], "root_cause_files": ["tsdb/head.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "9289a7f2ff84779e98eccca7", "metadata": {"confidence": "weak", "created_at": "2026-09-29T07:11:40Z", "evidence": {"implementation_files": ["tsdb/head.go"], "related_tests": ["tsdb/head_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-29T14:06:59Z", "pr": 19858, "pr_url": "https://github.com/prometheus/prometheus/pull/19858"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["tsdb/head.go"], "pr_body": "When truncateWAL creates a checkpoint and the WAL reader hits a corrupted segment, wlog.Checkpoint returns a wrapped *wlog.CorruptionErr. The Head's error handling checked for *chunks.CorruptionErr instead, a distinct type from a different package, so the type assertion never matched and prometheus_tsdb_wal_corruptions_total was never incremented. The corruption was still logged and returned, but the metric stayed at 0, meaning alerts on this metric never fired for corruption detected during checkpointing. Only the restart/replay path (which increments the counter unconditionally before repairing) would eventually surface it.\n\nCheck for *wlog.CorruptionErr, matching what wlog.Checkpoint actually returns and mirroring the agent's equivalent handling in tsdb/agent/db.go.\n\nAdds a test that corrupts a WAL segment on disk after a clean replay and asserts the metric is incremented when truncateWAL next checkpoints.\n\n#### Release notes for end users (**ALL** commits must be considered).\n```release-notes\n[BUGFIX] TSDB: Increment `prometheus_tsdb_wal_corruptions_total` when WAL corruption is detected during checkpoint creation, so the metric reflects corruption found at compaction time rather than only after a restart-triggered repair.\n```", "pr_title": "tsdb: fix WAL corruptions metric not incrementing on checkpoint creation"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "466be3beb37099c28804608966f894b0dbad9993", "candidate_corpus": {"base_commit": "466be3beb37099c28804608966f894b0dbad9993", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "b50814fd7d2d079ff3a5fdc10a50cda7925a29ba", "negative_distractors": [], "related_tests": ["tsdb/querier_test.go"], "root_cause_files": ["tsdb/querier.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "3f2d94c9619e0028711315dd", "metadata": {"confidence": "weak", "created_at": "2026-09-28T16:27:54Z", "evidence": {"implementation_files": ["tsdb/querier.go"], "related_tests": ["tsdb/querier_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-16T07:44:07Z", "pr": 19855, "pr_url": "https://github.com/prometheus/prometheus/pull/19855"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["tsdb/querier.go"], "pr_body": "Add regression coverage for reusing `DeletedIterator` by resetting its exported `Iter` and `Intervals` fields. This is the pattern used by [Thanos compactv2](https://github.com/thanos-io/thanos/blob/6d366a488c1c4f648c2aa2fc973060c627f8608e/pkg/compactv2/modifiers.go#L192-L209) when rewriting chunks.\n\nThe test covers both `Next` and `Seek`, with repeated timestamp ranges and successive chunks. Each case reuses one wrapper across two chunks and verifies every surviving timestamp and value, exhaustion, and the absence of iterator errors.\n\nAlso document that `DeletedIterator` can be reused.\n\n#### Which issue(s) does the PR fix:\n\nRefs #19550\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n```release-notes\nNONE\n```", "pr_title": "tsdb: test and document DeletedIterator reuse"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "dff7878b9e3c236605e597297e0e61c4b0eff48f", "candidate_corpus": {"base_commit": "dff7878b9e3c236605e597297e0e61c4b0eff48f", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "c45b13bbdd96b47a5441000fb454dce42894349d", "negative_distractors": [], "related_tests": ["tsdb/head_test.go"], "root_cause_files": ["tsdb/head_read.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "36199390c80d7be9b87a50c4", "metadata": {"confidence": "weak", "created_at": "2026-09-28T14:44:55Z", "evidence": {"implementation_files": ["tsdb/head_read.go"], "related_tests": ["tsdb/head_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-29T14:56:20Z", "pr": 19854, "pr_url": "https://github.com/prometheus/prometheus/pull/19854"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["tsdb/head_read.go"], "pr_body": "Head chunk iterators hide samples from appends that a querier must not see, by stopping after the samples that were committed when the querier was created. The wrapper that enforces this only overrode `Next`, so its `Seek` came from the wrapped chunk iterator. That `Seek` could move past the stop point without counting the samples it skipped. A query that seeks within a head chunk could therefore return samples committed after the query started, both from `Seek` itself and from the `Next` calls that follow.\n\n`Seek` now advances with `Next`, so it stops at the same point. The wrapper is only used when a head chunk has samples the querier must not see, so the common path is unaffected.\n\n`TestIsolationSeek` creates queriers, commits more samples to the same head chunk, and then seeks, with and without trimming the chunk to the query range. It fails on main in 4 of its 6 cases.\n\n#### Which issue(s) does the PR fix:\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n```release-notes\n[BUGFIX] TSDB: Fix queries that seek within a head chunk returning samples committed after the query started\n```", "pr_title": "tsdb: respect isolation when seeking in head chunks"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "270db29150547af8dc2f7695382068525c95361c", "candidate_corpus": {"base_commit": "270db29150547af8dc2f7695382068525c95361c", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "e66610b3295460aea47cf5a3db58665fc86c073f", "negative_distractors": ["tsdb/ooo_head_read.go", "tsdb/querier.go"], "related_tests": ["promql/promqltest/test.go", "promql/promqltest/test_test.go"], "root_cause_files": ["tsdb/db.go", "tsdb/head.go", "tsdb/head_read.go", "tsdb/ooo_head_read.go", "tsdb/querier.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "5b00b93ddbeefac8271106f9", "metadata": {"confidence": "weak", "created_at": "2026-09-26T08:14:04Z", "evidence": {"implementation_files": ["tsdb/db.go", "tsdb/head.go", "tsdb/head_read.go", "tsdb/ooo_head_read.go", "tsdb/querier.go"], "related_tests": ["promql/promqltest/test.go", "promql/promqltest/test_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "cross_directory_test"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-01T08:59:47Z", "pr": 19842, "pr_url": "https://github.com/prometheus/prometheus/pull/19842"}, "query": {"changed_file_summary": "5 implementation files and 2 existing test files changed within 7 total files.", "implementation_file_count": 5, "implementation_files": ["tsdb/db.go", "tsdb/head.go", "tsdb/head_read.go", "tsdb/ooo_head_read.go", "tsdb/querier.go"], "pr_body": "Queriers over the TSDB head, and the index and chunk readers they share, are not safe for concurrent use from multiple goroutines, since the head readers keep per-reader buffers and caches. This has been the case since #18302, where krajorama [asked in review](https://github.com/prometheus/prometheus/pull/18302#discussion_r3093280292) for the readers to be documented as no longer thread safe. That was only done on the unexported reader types.\n\nDocument it on the exported entry points that return or wrap head readers: `DB.Querier` and `DB.ChunkQuerier`, `DBReadOnly.Querier` and `DBReadOnly.ChunkQuerier`, `Head.Index` and `Head.Chunks`, `RangeHead`, `NewBlockQuerier` and `NewBlockChunkQuerier` when given a head, and the `HeadAndOOO*` readers and queriers.\n\nAlso document it on `promqltest.RunBuiltinTests`, `RunTest` and `LoadedStorage`, whose storage is a TSDB. Export the storage that `RunBuiltinTests` uses as `NewBuiltinTestStorage`, so engines that use a querier from multiple goroutines can wrap it and pass it to `RunBuiltinTestsWithStorage` without copying its TSDB options. `TestLoadSTLine_StorageRoundtrip` now also runs against it.\n\n#### Which issue(s) does the PR fix:\n\nRefers to #19840.\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n```release-notes\nNONE\n```", "pr_title": "tsdb, promqltest: document that head queriers are not safe for concurrent use"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "b273ae3adeb64ad630d65ef7f16440df95658410", "candidate_corpus": {"base_commit": "b273ae3adeb64ad630d65ef7f16440df95658410", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "ed04b4a7d5babe2cc14ad7f946b1865ddaed9f9a", "negative_distractors": ["web/federate.go", "web/ui/react-app/config-overrides.js"], "related_tests": ["model/textparse/protobufparse_test.go", "tsdb/agent/db_test.go", "web/federate_test.go"], "root_cause_files": ["model/textparse/protobufparse.go", "tsdb/agent/db.go", "tsdb/head_wal.go", "web/federate.go", "web/ui/react-app/config-overrides.js"], "root_cause_symbols": [], "supporting_files": ["go.mod", "go.sum", "web/ui/mantine-ui/package.json", "web/ui/pnpm-lock.yaml", "web/ui/pnpm-workspace.yaml", "web/ui/react-app/package.json", "web/ui/react-app/pnpm-lock.yaml", "web/ui/react-app/pnpm-workspace.yaml", "web/ui/react-app/src/config-overrides.test.js"]}, "id": "053bbe4cba0083f5f160217f", "metadata": {"confidence": "weak", "created_at": "2026-09-25T12:42:38Z", "evidence": {"implementation_files": ["model/textparse/protobufparse.go", "tsdb/agent/db.go", "tsdb/head_wal.go", "web/federate.go", "web/ui/react-app/config-overrides.js"], "related_tests": ["model/textparse/protobufparse_test.go", "tsdb/agent/db_test.go", "web/federate_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-28T09:06:16Z", "pr": 19834, "pr_url": "https://github.com/prometheus/prometheus/pull/19834"}, "query": {"changed_file_summary": "5 implementation files and 3 existing test files changed within 17 total files.", "implementation_file_count": 5, "implementation_files": ["model/textparse/protobufparse.go", "tsdb/agent/db.go", "tsdb/head_wal.go", "web/federate.go", "web/ui/react-app/config-overrides.js"], "pr_body": "#### Which issue(s) does the PR fix:\n\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n\n```release-notes\nNONE\n```", "pr_title": "[LTS] Backports and security updates"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "a0e6979d8d906f7cf3da331f7e962177e07a40e4", "candidate_corpus": {"base_commit": "a0e6979d8d906f7cf3da331f7e962177e07a40e4", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "270db29150547af8dc2f7695382068525c95361c", "negative_distractors": [], "related_tests": ["promql/parser/parse_test.go"], "root_cause_files": ["promql/parser/features.go", "promql/parser/parse.go"], "root_cause_symbols": [], "supporting_files": ["promql/parser/features_test.go"]}, "id": "d733ae2cdee87840d9d7bcce", "metadata": {"confidence": "weak", "created_at": "2026-09-25T04:54:19Z", "evidence": {"implementation_files": ["promql/parser/features.go", "promql/parser/parse.go"], "related_tests": ["promql/parser/parse_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-25T14:26:37Z", "pr": 19830, "pr_url": "https://github.com/prometheus/prometheus/pull/19830"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["promql/parser/features.go", "promql/parser/parse.go"], "pr_body": "## What\n\nThis adds a `Functions` field to `parser.Options`, so a parser can be created with its own set of functions:\n\n```go\nfuncs := maps.Clone(parser.Functions)\nmaps.Copy(funcs, engineFunctions)\np := parser.NewParser(parser.Options{Functions: funcs})\n```\n\n- **Existing callers are unaffected.** A nil `Functions` keeps using the default `parser.Functions` set.\n- **A non-nil map replaces the default set.** These are the same semantics `parser.WithFunctions` had. An empty map accepts no functions.\n- **`NewParser` copies the map.** Later changes to the caller's map cannot affect parsing or race with it.\n- **`RegisterFeatures` reports what the parser actually accepts.** It lists the functions from this parser's set, not the global one.\n\n## Why\n\n#12170 added `parser.WithFunctions` for downstream PromQL engines. The Thanos engine, thanos-io/promql-engine, uses it to parse its extra `xrate`, `xincrease` and `xdelta` functions without adding them to the global `parser.Functions` map. Adding them there would make them parseable by every other parser in the process, including the Prometheus engine's.\n\n#17977 moved parser configuration into `parser.Options` and dropped `WithFunctions`. I couldn't find any discussion of the removal in that PR, so it looks incidental. Since then, the only way left is to mutate the global map. @GiedriusS asked about this on #17977 ([comment](https://github.com/prometheus/prometheus/pull/17977#issuecomment-5056989925)). It is what currently keeps thanos-io/promql-engine and Thanos, and in turn Cortex, from moving past Prometheus 3.10.\n\nThe internal `newParserWithFunctions` helper survived the refactor, so this change only exposes that capability through the options. The helper, which was left with no callers outside a test, is removed.\n\n## Test\n\n- **`\n...[truncated]", "pr_title": "promql/parser: allow custom functions via parser.Options"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "a0e6979d8d906f7cf3da331f7e962177e07a40e4", "candidate_corpus": {"base_commit": "a0e6979d8d906f7cf3da331f7e962177e07a40e4", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "5c5be17a214a17319dafac23c4dc0671299a241f", "negative_distractors": [], "related_tests": ["promql/functions_test.go"], "root_cause_files": ["promql/functions.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "abde7a58fbfaa09832008421", "metadata": {"confidence": "weak", "created_at": "2026-09-24T22:07:08Z", "evidence": {"implementation_files": ["promql/functions.go"], "related_tests": ["promql/functions_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-29T12:37:46Z", "pr": 19828, "pr_url": "https://github.com/prometheus/prometheus/pull/19828"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["promql/functions.go"], "pr_body": "**What**\n- Fix `ts_of_last_over_time` for samples before the Unix epoch.\n\n**Why**\n- Missing timestamps defaulted to zero, which wins over negative sample timestamps.\n\n**Implementation**\n- Initialize missing float and histogram timestamps to `math.MinInt64`.\n\n```release-notes\n[BUGFIX] Fix ts_of_last_over_time for samples before the Unix epoch.\n```", "pr_title": "promql: fix ts_of_last_over_time before Unix epoch"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "f03f0e4b5b5f18ca02056b3510f82803475883da", "candidate_corpus": {"base_commit": "f03f0e4b5b5f18ca02056b3510f82803475883da", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "a0e6979d8d906f7cf3da331f7e962177e07a40e4", "negative_distractors": [], "related_tests": ["web/ui/module/codemirror-promql/src/complete/hybrid.test.ts"], "root_cause_files": ["web/ui/module/codemirror-promql/src/complete/hybrid.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "2286b3891fa4f9b1db702676", "metadata": {"confidence": "weak", "created_at": "2026-09-24T13:53:12Z", "evidence": {"implementation_files": ["web/ui/module/codemirror-promql/src/complete/hybrid.ts"], "related_tests": ["web/ui/module/codemirror-promql/src/complete/hybrid.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-24T15:43:56Z", "pr": 19825, "pr_url": "https://github.com/prometheus/prometheus/pull/19825"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["web/ui/module/codemirror-promql/src/complete/hybrid.ts"], "pr_body": "Currently when you type `rate(foo[5m])`, there is immediately an autocompletion dropdown suggesting all binary operators. Similar for aggregation op modifiers if an aggregation doesn't have a modifier yet. This changes it such that the dropdown only opens in this case if the user explicitly requests it (Ctrl+Space).\n\nThe annoying behavior:\n\nhttps://github.com/user-attachments/assets/dc189b6b-f612-48d3-800f-0e49490ac68a\n\nCC @MichaHoffmann, this seems to have gotten added in https://github.com/prometheus/prometheus/pull/18894/\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n\n```release-notes\n[BUGFIX] UI: Don't automatically open an autocomplete dropdown after closing a function call body or aggregation operator with a closing parenthesis.\n```", "pr_title": "UI: Fix overeager autocompletion after closing parenthesis"}, "query_provenance": "pr_summary", "repo": "prometheus/prometheus", "task_type": "code2test", "version": 2} +{"base_commit": "cfeea823ea175900fcdb2109c05eacfa354625bd", "candidate_corpus": {"base_commit": "cfeea823ea175900fcdb2109c05eacfa354625bd", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "190471268eccc24ae398de812c2667748f43f4be", "negative_distractors": [], "related_tests": ["crates/nu-command/tests/commands/use_.rs"], "root_cause_files": ["crates/nu-command/src/system/run_external.rs", "crates/nu-mcp/src/evaluation.rs", "crates/nu-protocol/src/engine/engine_state.rs"], "root_cause_symbols": [], "supporting_files": []}, "id": "2fb021b0ceec0ac2131b369b", "metadata": {"confidence": "weak", "created_at": "2026-10-16T16:47:01Z", "evidence": {"implementation_files": ["crates/nu-command/src/system/run_external.rs", "crates/nu-mcp/src/evaluation.rs", "crates/nu-protocol/src/engine/engine_state.rs"], "related_tests": ["crates/nu-command/tests/commands/use_.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-16T17:09:30Z", "pr": 19270, "pr_url": "https://github.com/nushell/nushell/pull/19270"}, "query": {"changed_file_summary": "3 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 3, "implementation_files": ["crates/nu-command/src/system/run_external.rs", "crates/nu-mcp/src/evaluation.rs", "crates/nu-protocol/src/engine/engine_state.rs"], "pr_body": "## Description\n\nFollow-up to #19262. Three problems remain in how the MCP server's `list_commands` and `command_help` tools, and the \"Did you mean\" hint for an unknown command, describe the commands in scope.\n\n- **Hidden commands are still offered.** `EngineState::get_decls_sorted(false)` checks each overlay only against that overlay's own visibility, but `hide` records the hide in the overlay that is active when it runs. After `alias st = str trim`, `overlay new x`, `hide st` (entered as separate lines), `st` can't be called, yet MCP lists it, `command_help st` documents it, and `' a ' | st` says \"Did you mean `st`?\". Module commands hidden the same way behave the same.\n- **`command_help` can describe the wrong command.** It searched the listed signatures for a matching name instead of resolving the name the way the parser does. When an overlay shadows `foo` and a later overlay hides that `foo`, a call to `foo` runs the original, but `command_help foo` documented the shadowing one. If a command was hidden and then imported again from a later overlay, `foo` ran but `command_help foo` said it didn't exist.\n- **An alias lists the arguments it already passes.** An alias of an internal command carries the wrapped command's full signature. `alias home = cd ~` was listed as `home {flags} (path)`, and `def \"foo bar\" [x: int] {}; alias fb = foo bar 1` as `fb `. The parser starts matching an alias call's arguments after the positionals the alias passes (`parse_internal_call`), so `home /tmp` and `fb 2` fail.\n\n## User-facing changes (Release notes)\n\n- The MCP server's `list_commands` and `command_help` tools, and the \"Did you mean\" hint for an unknown command, no longer offer a command that was hidden with `hide` while another overlay was active.\n- `command_help` now describe\n...[truncated]", "pr_title": "fix(mcp): don't offer hidden commands, and leave out the arguments an alias already passes"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "07b01e2f376c0b2a84522720ebf3e5e4eeff7674", "candidate_corpus": {"base_commit": "07b01e2f376c0b2a84522720ebf3e5e4eeff7674", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "6112446c3c409933c9a7338cd7d00258991b3be3", "negative_distractors": [], "related_tests": ["crates/nu-command/tests/commands/help.rs", "tests/shell/mod.rs"], "root_cause_files": ["crates/nu-engine/src/documentation.rs"], "root_cause_symbols": [], "supporting_files": []}, "id": "322e0f328d2add6acf1a19c1", "metadata": {"confidence": "weak", "created_at": "2026-10-16T12:12:58Z", "evidence": {"implementation_files": ["crates/nu-engine/src/documentation.rs"], "related_tests": ["crates/nu-command/tests/commands/help.rs", "tests/shell/mod.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-16T12:47:23Z", "pr": 19261, "pr_url": "https://github.com/nushell/nushell/pull/19261"}, "query": {"changed_file_summary": "1 implementation files and 2 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["crates/nu-engine/src/documentation.rs"], "pr_body": "## Description\n\nFollow-up to #19253, which lists an alias in `help ` under its own name, right after the subcommand it runs. Four cases are still wrong on main:\n\n- A hidden custom subcommand is still listed. #19253 only dropped hidden aliases.\n- An alias written over several lines splits its entry across lines.\n- With color on, backticks inside an alias's expansion confuse the highlighter. The inner backticks disappear and the outer ones stay.\n- A script's `alias mb = main bar` is missing from `script.nu --help`, though `mb` works inside the script.\n\nWith this PR, `help` leaves out a hidden subcommand of any kind, joins an alias's expansion onto one line and highlights it as a whole, and lists a script alias of a `main` subcommand right after that subcommand.\n\nEach example shows the Subcommands section of `help`. Before is main at 776da6de4 (which includes #19253), after is this branch. Color is stripped.\n\nA hidden custom subcommand was still listed. You can't call it, so it's left out now.\n\n```nushell\ndef foo [] {}; def \"foo bar\" [] {}; def \"foo qux\" [] {}; hide \"foo qux\"; help foo\n```\n\nBefore:\n\n```nushell\nSubcommands:\n foo bar (custom) -\n foo qux (custom) -\n```\n\nAfter:\n\n```nushell\nSubcommands:\n foo bar (custom) -\n```\n\nAn alias written over several lines split its entry across lines. The entry joins them now.\n\n```nushell\ndef foo [] {}; def \"foo bar\" [x] {}\nalias fm = foo bar (\n 'a'\n)\nhelp foo\n```\n\nBefore:\n\n```nushell\nSubcommands:\n foo bar (custom) -\n fm (alias) - Alias for `foo bar (\n 'a'\n)`\n```\n\nAfter:\n\n```nushell\nSubcommands:\n foo bar (custom) -\n fm (alias) - Alias for foo bar ( 'a' )\n```\n\nBackticks inside the expansion lost their place. The highlighter dropped the inner pair and kept the outer one.\n\n```nushell\ndef foo [] {}; def \"foo bar\" [x] {}; a\n...[truncated]", "pr_title": "fix(help): drop hidden subcommands and fix multi-line, backticked, and script alias entries"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "afc9a5d49f89418c5f1ca50b7b48865672fb24cc", "candidate_corpus": {"base_commit": "afc9a5d49f89418c5f1ca50b7b48865672fb24cc", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "f5affecddc93241fc5055765713145d25f815689", "negative_distractors": [], "related_tests": ["tests/modules/mod.rs"], "root_cause_files": ["crates/nu-parser/src/parse_module.rs"], "root_cause_symbols": [], "supporting_files": []}, "id": "b3a963aeb0dab72893b824d2", "metadata": {"confidence": "weak", "created_at": "2026-10-13T15:58:20Z", "evidence": {"implementation_files": ["crates/nu-parser/src/parse_module.rs"], "related_tests": ["tests/modules/mod.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-14T21:16:02Z", "pr": 19228, "pr_url": "https://github.com/nushell/nushell/pull/19228"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["crates/nu-parser/src/parse_module.rs"], "pr_body": "Check each module once when deciding whether to reload a cached module\n\n## Description\n\nWhen a module that has already been parsed is imported again, `parse_module_file` calls `module_needs_reloading` to check whether any file in the module's tree has changed on disk. That walk recurses through `submodules` and `imported_modules` without tracking which modules it has visited, so a module reachable through several paths is re-read once per *path*.\n\nThat's common in practice: a `mod.nu` that `export use`s its sibling files, where most siblings also `use` a few shared helpers. In the repro from the issue, every extra `use nested` of a 9-file module re-reads its files ~133 times; with a real 22-file library it's ~412 reads per import. Linux mostly hides this because file opens are cheap, but on Windows it dominates parse time, and the LSP pays it on every keystroke.\n\nThis PR adds a `seen` set for the duration of the walk, so each reachable module's file is read at most once per check. Skipping an already-seen module is safe: `any()` short-circuits on the first change, so a module seen again has already been found unchanged. I also extracted the read-and-compare into a separate `module_file_changed` function.\n\nMeasured on Windows with the repro script from the issue (`nu -n repro.nu`):\n\n| importers | before | after |\n| --------: | -----: | ----: |\n| 1 | 34.9 ms | 28.4 ms |\n| 2 | 51.2 ms | 29.2 ms |\n| 5 | 97.5 ms | 32.4 ms |\n| 10 | 179.0 ms | 38.3 ms |\n\nPer extra importer: **16.0 ms → 1.1 ms**. In my real-world case (a 13-file module importing a 22-file library from most of its files), parsing on Windows went from ~3.1 s to the point where the LSP is responsive again.\n\n## User-facing changes (Release notes)\n\nImproved performance when the same module is imported from many plac\n...[truncated]", "pr_title": "Optimize module reloading check"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "af37214641d62d104523ce36eeaac6a6323a005a", "candidate_corpus": {"base_commit": "af37214641d62d104523ce36eeaac6a6323a005a", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "e56aca9da6c068b6c6d33bbb70bd1da82b7fd483", "negative_distractors": [], "related_tests": ["crates/nu-command/tests/commands/table/display.rs", "crates/nu-table/tests/constrains.rs"], "root_cause_files": ["crates/nu-table/src/table.rs", "crates/nu-table/src/types/expanded.rs"], "root_cause_symbols": [], "supporting_files": []}, "id": "20d928f35a4b7f926dabcfb2", "metadata": {"confidence": "weak", "created_at": "2026-10-11T13:28:27Z", "evidence": {"implementation_files": ["crates/nu-table/src/table.rs", "crates/nu-table/src/types/expanded.rs"], "related_tests": ["crates/nu-command/tests/commands/table/display.rs", "crates/nu-table/tests/constrains.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-11T18:50:21Z", "pr": 19212, "pr_url": "https://github.com/nushell/nushell/pull/19212"}, "query": {"changed_file_summary": "2 implementation files and 2 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["crates/nu-table/src/table.rs", "crates/nu-table/src/types/expanded.rs"], "pr_body": "## Description\n\n`open Cargo.toml | [ $in ] | table -e -w 183` on main grows memory until the OOM killer ends nu. A debug build panics instead.\n\n### Before, debug build of main:\n\n```nushell\n> open Cargo.toml | [ $in ] | table -e -w 183 | ignore\nError: × Main thread panicked.\n ├─▶ at .../papergrid-0.18.0/src/grid/peekable.rs:985:20\n ╰─▶ attempt to subtract with overflow\n```\n\nBefore, release build of main (0.116.2 at 251b39276): no output, RSS climbs about 390 MB a second (406 MB after 1 s, 2.35 GB after 6 s) until killed. After, release build of this branch: 0.02 s, 24 MB peak RSS.\n\n### After:\n\n```nushell\n> open Cargo.toml | [ $in ] | table -e -w 183\n╭───┬────────────┬─────────────┬────────────┬────────────┬──────────────┬────────────┬───────────────┬────────────┬────────────┬────────────┬───────────┬────────────┬────────────────╮\n│ # │ package │ test │ workspace │ lints │ dependencies │ target │ build-depende │ dev-depend │ features │ profile │ bin │ patch │ bench │\n│ │ │ │ │ │ │ │ ncies │ encies │ │ │ │ │ │\n├───┼────────────┼─────────────┼────────────┼────────────┼──────────────┼────────────┼───────────────┼────────────┼────────────┼────────────┼───────────┼────────────┼────────────────┤\n│ 0 │ {record 15 │ ╭───┬─────╮ │ {record 4 │ {record 1 │ {record 33 │ {record 2 │ {record 1 │ {record 12 │ {record 14 │ {record 3 │ [table 1 │ {record 1 │ ╭───┬────────╮ │\n│ │ fields} │ │ # │ ... │ │ fields} │ field} │ fields} │ fields} │ field} │ fields} │ fields} │ fields} │ row] │ field} │ │ # │ name │ │\n│ │ │ ├───┼─────┤ │\n...[truncated]", "pr_title": "fix(table): stop `table --expand` hanging when a nested table is wider than its column"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "9149ea5ede28cd618886ebd0e767ba90694515ca", "candidate_corpus": {"base_commit": "9149ea5ede28cd618886ebd0e767ba90694515ca", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "c3b7a5aebea0119d88bba4608bc6a3f81bb54a45", "negative_distractors": [], "related_tests": ["crates/nu-command/tests/commands/str_/into_string.rs"], "root_cause_files": ["crates/nu-command/src/conversions/into/string.rs"], "root_cause_symbols": [], "supporting_files": []}, "id": "bba36261973f5477d7672f82", "metadata": {"confidence": "weak", "created_at": "2026-10-08T15:49:25Z", "evidence": {"implementation_files": ["crates/nu-command/src/conversions/into/string.rs"], "related_tests": ["crates/nu-command/tests/commands/str_/into_string.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-09T16:49:32Z", "pr": 19191, "pr_url": "https://github.com/nushell/nushell/pull/19191"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["crates/nu-command/src/conversions/into/string.rs"], "pr_body": "## Description\n\n`into string -d ` panics when the precision is large enough that `10_f64.powi(precision as i32)` underflows to zero. The division then produces NaN, and `format!(\"{:.*}\", precision, NaN)` panics with \"Formatting argument out of range\".\n\nRepro: `1.5 | into string -d 2147483648`\n\nThe `i64` precision is cast to `i32` for `powi`, so values above `i32::MAX` wrap to negative, producing `10^(-2147483648) = 0`, then `NaN`. The `is_finite()` guard earlier in the function only checks the input value, not the rounded result.\n\nReturn the original value's string form when the rounding produces NaN.\n\n## User-facing changes\n\n`into string` with a very large `-d` value no longer panics; it returns the unrounded value.\n\n## Additional notes\n\nVerified with a standalone Rust repro that `(1.5 * 10^(-2147483648)).round() / 10^(-2147483648)` is NaN and `format!(\"{:.*}`, 2147483648, NaN)` panics.", "pr_title": "fix: reject out-of-range decimals in into string"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "c14a6f383633c4828532c69e08cd779d11094484", "candidate_corpus": {"base_commit": "c14a6f383633c4828532c69e08cd779d11094484", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "85aae22da8e8c010e782d011b07c46bc7d703fb8", "negative_distractors": ["crates/nu-plugin-core/src/interface/tests.rs", "crates/nu-plugin-core/src/lib.rs", "crates/nu-plugin/src/plugin/command.rs", "crates/nu-plugin/src/plugin/interface/mod.rs", "crates/nu-plugin/src/plugin/interface/tests.rs", "crates/nu-plugin/src/plugin/mod.rs"], "related_tests": ["crates/nu-plugin-core/src/interface/test_util.rs", "crates/nu-plugin-test-support/src/spawn_fake_plugin.rs"], "root_cause_files": ["crates/nu-plugin-core/src/interface/mod.rs", "crates/nu-plugin-core/src/interface/stream/mod.rs", "crates/nu-plugin-core/src/interface/stream/tests.rs", "crates/nu-plugin-core/src/interface/tests.rs", "crates/nu-plugin-core/src/lib.rs", "crates/nu-plugin/src/plugin/command.rs", "crates/nu-plugin/src/plugin/interface/mod.rs", "crates/nu-plugin/src/plugin/interface/tests.rs"], "root_cause_symbols": [], "supporting_files": ["crates/nu-plugin/src/plugin/mod.rs", "crates/nu-plugin-test-support/src/spawn_fake_plugin/tests.rs"]}, "id": "da821ef6aa1a92000edd8396", "metadata": {"confidence": "weak", "created_at": "2026-10-06T10:56:55Z", "evidence": {"implementation_files": ["crates/nu-plugin-core/src/interface/mod.rs", "crates/nu-plugin-core/src/interface/stream/mod.rs", "crates/nu-plugin-core/src/interface/stream/tests.rs", "crates/nu-plugin-core/src/interface/tests.rs", "crates/nu-plugin-core/src/lib.rs", "crates/nu-plugin/src/plugin/command.rs", "crates/nu-plugin/src/plugin/interface/mod.rs", "crates/nu-plugin/src/plugin/interface/tests.rs", "crates/nu-plugin/src/plugin/mod.rs"], "related_tests": ["crates/nu-plugin-core/src/interface/test_util.rs", "crates/nu-plugin-test-support/src/spawn_fake_plugin.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-16T18:21:09Z", "pr": 19171, "pr_url": "https://github.com/nushell/nushell/pull/19171"}, "query": {"changed_file_summary": "9 implementation files and 2 existing test files changed within 12 total files.", "implementation_file_count": 9, "implementation_files": ["crates/nu-plugin-core/src/interface/mod.rs", "crates/nu-plugin-core/src/interface/stream/mod.rs", "crates/nu-plugin-core/src/interface/stream/tests.rs", "crates/nu-plugin-core/src/interface/tests.rs", "crates/nu-plugin-core/src/lib.rs", "crates/nu-plugin/src/plugin/command.rs", "crates/nu-plugin/src/plugin/interface/mod.rs", "crates/nu-plugin/src/plugin/interface/tests.rs"], "pr_body": "## Description\n\nA plugin can stop processing while its input reader is still blocked on a connected, idle producer.\n\nHave the SDK release a call's original list or byte input automatically when its complete response finishes writing, or when the engine drops its output stream. Returning lazy output does not itself release input. Other calls and engine-call result streams are unaffected; no new public plugin API is needed.\n\nDefer both completion and output-drop cleanup while the SDK is forwarding stream input to an engine call. An early response from `call_decl` or `eval_closure_with_stream` must not truncate that input, including redirected output that closes before its input consumer finishes. The core reader owns a concrete hold, attached before publishing the engine-call header and released when the forwarding writer ends or its consumer sends `Drop`. Since `PipelineData` is opaque, forwarding an unrelated stream conservatively holds the original input too. Engine-call result readers remain outside this cleanup.\n\nSkip completion cleanup while the plugin has disabled GC through `set_gc_disabled(true)`, preserving background input reads after a response. This follows the last successfully written and flushed plugin-wide GC option, not Nushell's GC configuration. The setting is shared by all calls, so overlapping calls must coordinate updates: the last write wins for both GC and input retention. Completion reads the setting without waiting for transport I/O; concurrent GC updates retain their wire order. An early output `Drop` still requests input cleanup, regardless of GC, but honors active SDK forwarding holds. Remove the output/input association before sending `End`, so a normal EOF acknowledgement does not cancel those background reads. Keep the association in the o\n...[truncated]", "pr_title": "Release plugin inputs on response completion or output drop"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "c14a6f383633c4828532c69e08cd779d11094484", "candidate_corpus": {"base_commit": "c14a6f383633c4828532c69e08cd779d11094484", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "15b810275b6759d4b6de85c5da0cfacee5fff407", "negative_distractors": [], "related_tests": ["crates/nu-command/tests/commands/str_/into_string.rs"], "root_cause_files": ["crates/nu-command/src/conversions/into/string.rs", "crates/nu-command/src/math/round.rs"], "root_cause_symbols": [], "supporting_files": []}, "id": "cdb84b7e095d7dcfc400efce", "metadata": {"confidence": "weak", "created_at": "2026-10-05T17:40:14Z", "evidence": {"implementation_files": ["crates/nu-command/src/conversions/into/string.rs", "crates/nu-command/src/math/round.rs"], "related_tests": ["crates/nu-command/tests/commands/str_/into_string.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-06T14:52:41Z", "pr": 19166, "pr_url": "https://github.com/nushell/nushell/pull/19166"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 2, "implementation_files": ["crates/nu-command/src/conversions/into/string.rs", "crates/nu-command/src/math/round.rs"], "pr_body": "## Description\n\nFix #16772 by implementing string-based decimal grouping for `into string` on floats and adding locale support.\n\nBecause floating point conversion into decimal strings is tricky, continue to use Rust's implementation, then modify it's output with grouping and locale strings.\n\nThe rounding behavior of into string was also inconsistent with `math round`. See these results:\n```\n[[base]; [0.5] [1.5]]\n | insert math {$in.base | math round}\n | insert str { $in.base | into string -d 0}\n\n # base math str\n───────────────────────\n 0 0.50 1 0\n 1 1.50 2 2\n```\nManually round the floats in the same manner in both places. Update to use the slightly more efficient `f64.powi()` method instead of `f64.powf()`.\n\n## User-facing changes (Release notes)\nAdded support to `into string` for locales and `--group-digits` with floating point input. Made the `into string` rounding match `math round`.\n\n## Additional notes\nfixes #16772", "pr_title": "Correct float `into string` conversions"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "818d4ac0644a03e857062b024c136c5d27ba0ea5", "candidate_corpus": {"base_commit": "818d4ac0644a03e857062b024c136c5d27ba0ea5", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "356e7bc02ff05b127b192af4a8c8b34efac21699", "negative_distractors": ["crates/nu-cli/src/util.rs", "crates/nu-command/src/experimental/job_spawn.rs", "crates/nu-command/src/system/run_external.rs", "crates/nu-engine/src/exit.rs", "crates/nu-protocol/src/engine/engine_state.rs", "crates/nu-protocol/src/engine/jobs.rs", "crates/nu-system/src/foreground.rs", "src/command.rs"], "related_tests": ["tests/shell/mod.rs"], "root_cause_files": ["crates/nu-cli/src/config_files.rs", "crates/nu-cli/src/eval_cmds.rs", "crates/nu-cli/src/eval_file.rs", "crates/nu-cli/src/util.rs", "crates/nu-command/src/experimental/job_spawn.rs", "crates/nu-command/src/system/run_external.rs", "crates/nu-engine/src/exit.rs", "crates/nu-protocol/src/engine/engine_state.rs"], "root_cause_symbols": [], "supporting_files": ["crates/nu-protocol/src/engine/jobs.rs", "crates/nu-system/src/foreground.rs", "src/command.rs", "src/config_files.rs", "src/main.rs", "src/run.rs", "src/signals.rs", "Cargo.toml", "tests/shell/background_jobs.rs"]}, "id": "5883d4e6daf507b0923d1e6e", "metadata": {"confidence": "weak", "created_at": "2026-10-05T16:32:46Z", "evidence": {"implementation_files": ["crates/nu-cli/src/config_files.rs", "crates/nu-cli/src/eval_cmds.rs", "crates/nu-cli/src/eval_file.rs", "crates/nu-cli/src/util.rs", "crates/nu-command/src/experimental/job_spawn.rs", "crates/nu-command/src/system/run_external.rs", "crates/nu-engine/src/exit.rs", "crates/nu-protocol/src/engine/engine_state.rs", "crates/nu-protocol/src/engine/jobs.rs", "crates/nu-system/src/foreground.rs", "src/command.rs", "src/config_files.rs", "src/main.rs", "src/run.rs", "src/signals.rs"], "related_tests": ["tests/shell/mod.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-16T11:44:51Z", "pr": 19163, "pr_url": "https://github.com/nushell/nushell/pull/19163"}, "query": {"changed_file_summary": "15 implementation files and 1 existing test files changed within 18 total files.", "implementation_file_count": 15, "implementation_files": ["crates/nu-cli/src/config_files.rs", "crates/nu-cli/src/eval_cmds.rs", "crates/nu-cli/src/eval_file.rs", "crates/nu-cli/src/util.rs", "crates/nu-command/src/experimental/job_spawn.rs", "crates/nu-command/src/system/run_external.rs", "crates/nu-engine/src/exit.rs", "crates/nu-protocol/src/engine/engine_state.rs"], "pr_body": "## Summary\n\n- Addresses #18989 by preserving REPL background and frozen jobs during foreground `Ctrl-C`, while non-REPL commands and scripts clean up jobs even when an interruption is caught\n- Determine execution mode once (REPL, command, script, server) without conflating `-i` with an interactive REPL; explicit `exit` in `-i -c` or `-i` script preserves requested exit code, while REPL retains first-exit warning and second-exit cleanup\n- Serialize OS process creation and PID registration against `ThreadJob` shutdown under the PID lock to eliminate an orphan-process race\n- Clear cloned `is_repl` flag in background job engine clones so `exit` terminates their closure instead of warning and continuing\n- Centralize forced cleanup and lock-poison recovery, completing non-REPL cleanup before publishing interrupts while preserving early signal-handler initialization\n- Windows combines `CREATE_NEW_PROCESS_GROUP` and `CREATE_NO_WINDOW` inside `ForegroundChild` without an extra exported preparation helper; new process groups isolate `Ctrl-C` but `Ctrl+Break` is NOT isolated\n- Cross-platform lifecycle tests use Nu as the child, bounded handshakes and Windows owned process handles opened before child exit to avoid PID reuse\n- Add tests for lock registration, chained spawns, explicit exit, REPL two exits and background exit; remove fixed 500ms sleep\n- Fix minimal-feature plugin-only import warning for `absolute_with`\n\n## Testing\n\nVerified on macOS on top of `ca323a65bdb7c945488b75a5f7bf5d90a8f3bff1`:\n- 29 background job regressions, 3 `ThreadJob` tests, and 47 root unit tests passed\n- Shell suite: 320 passed, 6 ignored\n- Related crate tests and doctests ran with `--no-fail-fast` for `nu-protocol`, `nu-engine`, `nu-command`, `nu-system`, `nu-cli`; all passed except one existing `cp`\n...[truncated]", "pr_title": "Preserve REPL background jobs on Ctrl-C and clean up jobs on non-REPL exit"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "bd30843743bf1c9f46f67597eaa45fa7871571e2", "candidate_corpus": {"base_commit": "bd30843743bf1c9f46f67597eaa45fa7871571e2", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "b6671f5cdc19cead8bff054f86f01f97c121aabb", "negative_distractors": ["crates/nu-system/src/freebsd.rs", "crates/nu-system/src/lib.rs", "crates/nu-system/src/linux.rs", "crates/nu-system/src/macos.rs", "crates/nu-system/src/netbsd.rs", "crates/nu-system/src/process.rs", "crates/nu-system/src/unix.rs", "crates/nu-system/src/windows.rs"], "related_tests": ["crates/nu-command/tests/commands/job.rs"], "root_cause_files": ["crates/nu-command/src/platform/kill.rs", "crates/nu-command/src/system/ps.rs", "crates/nu-system/examples/sys_demo.rs", "crates/nu-system/src/freebsd.rs", "crates/nu-system/src/lib.rs", "crates/nu-system/src/linux.rs", "crates/nu-system/src/macos.rs", "crates/nu-system/src/netbsd.rs"], "root_cause_symbols": [], "supporting_files": ["crates/nu-system/src/process.rs", "crates/nu-system/src/unix.rs", "crates/nu-system/src/windows.rs", "Cargo.lock", "Cargo.toml", "README.md", "crates/nu-command/Cargo.toml", "crates/nu-config/default_files/doc_config.nu", "crates/nu-system/Cargo.toml"]}, "id": "5a97a4531da76dd4a1eb7695", "metadata": {"confidence": "weak", "created_at": "2026-10-03T20:22:12Z", "evidence": {"implementation_files": ["crates/nu-command/src/platform/kill.rs", "crates/nu-command/src/system/ps.rs", "crates/nu-system/examples/sys_demo.rs", "crates/nu-system/src/freebsd.rs", "crates/nu-system/src/lib.rs", "crates/nu-system/src/linux.rs", "crates/nu-system/src/macos.rs", "crates/nu-system/src/netbsd.rs", "crates/nu-system/src/process.rs", "crates/nu-system/src/unix.rs", "crates/nu-system/src/windows.rs"], "related_tests": ["crates/nu-command/tests/commands/job.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-05T13:08:10Z", "pr": 19145, "pr_url": "https://github.com/nushell/nushell/pull/19145"}, "query": {"changed_file_summary": "11 implementation files and 1 existing test files changed within 18 total files.", "implementation_file_count": 11, "implementation_files": ["crates/nu-command/src/platform/kill.rs", "crates/nu-command/src/system/ps.rs", "crates/nu-system/examples/sys_demo.rs", "crates/nu-system/src/freebsd.rs", "crates/nu-system/src/lib.rs", "crates/nu-system/src/linux.rs", "crates/nu-system/src/macos.rs", "crates/nu-system/src/netbsd.rs"], "pr_body": "## Description\n\nThis PR refactors the `ps` command and consolidates some code with `nu_system::ProcessInfo` while also making it more portable having the same columns on all operating systems with `ps` and `ps -l`. It also fixes some bugs where all the processes weren't being seen on MacOS. \n\nAlso there was some debate as to whether 0 was valid for cpu. `cpu` is the percent of one core used during a ~100ms sample, like `top`. Most processes are idle during any 100ms, and `/bin/ps` agrees. Per-process values won't always match `/bin/ps`: macOS's `%CPU` is the kernel's decaying recent average (a process stopped after 3 seconds at 100% shows 0.0 five seconds later), and Linux's `ps` shows lifetime average CPU.\n\n\n## User-facing changes (Release notes)\n\n- `ps` now lists every process on macOS (zombies included) and Windows (all but the System Idle Process), including other users' and protected processes. Values the operating system doesn't make available for a process (on macOS, the CPU, memory and threads of other users' processes unless you run as root) are null instead of the process being left out.\n- `ps` and `ps -l` now return the same columns on every platform. A column is null when the platform or the process doesn't provide that value.\n - `ps`: `pid ppid name user status cpu cpu_time mem`\n - `ps -l` adds: `virtual private command exe start_time user_id process_group_id session_id priority nice threads read written cwd environment`\n- New columns:\n - `cpu_time`: total CPU time the process has used.\n - `private`: the memory only the process uses, the number Activity Monitor and Task Manager show as \"Memory\".\n - `nice`: the nice value; on Windows, the priority class on the nice scale.\n - `read` and `written`: bytes of storage I/O since the process started (all I/O\n...[truncated]", "pr_title": "fix(ps): list every process and report the same columns on every platform"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "bd30843743bf1c9f46f67597eaa45fa7871571e2", "candidate_corpus": {"base_commit": "bd30843743bf1c9f46f67597eaa45fa7871571e2", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "fcbf51c4023a6504270f405ec46bfad7307e853a", "negative_distractors": [], "related_tests": ["crates/nu-command/tests/commands/into_datetime.rs"], "root_cause_files": ["crates/nu-command/src/conversions/into/datetime.rs"], "root_cause_symbols": [], "supporting_files": ["Cargo.lock", "Cargo.toml"]}, "id": "c0c545a1eb184caea5f0feca", "metadata": {"confidence": "weak", "created_at": "2026-10-02T16:22:21Z", "evidence": {"implementation_files": ["crates/nu-command/src/conversions/into/datetime.rs"], "related_tests": ["crates/nu-command/tests/commands/into_datetime.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-05T13:28:36Z", "pr": 19139, "pr_url": "https://github.com/nushell/nushell/pull/19139"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 1, "implementation_files": ["crates/nu-command/src/conversions/into/datetime.rs"], "pr_body": "## Description\n\nThis PR allows using all timezones from `date list-timezone` (from `chrono_tz::TZ_VARIANTS`) to be used in the `--timezone` flag for `into datetime`.\n\nThis also includes the completion to make it easy to use:\n\"timezone\n\n## User-facing changes (Release notes)\n\n`into datetime --timezone` now accepts all timezones from `date list-timezone`.\n\n## Additional notes\n\n- fixes #19132", "pr_title": "Allow `TZ_VARIANTS` in `into datetime --timezone`"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "1f2dd1f54a16903f8d39453201cb15e7744e6236", "candidate_corpus": {"base_commit": "1f2dd1f54a16903f8d39453201cb15e7744e6236", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "bd30843743bf1c9f46f67597eaa45fa7871571e2", "negative_distractors": ["crates/nu-system/src/lib.rs", "src/main.rs", "src/run.rs"], "related_tests": ["crates/nu-command/tests/commands/exec.rs", "tests/shell/mod.rs"], "root_cause_files": ["crates/nu-cli/src/repl.rs", "crates/nu-protocol/src/engine/engine_state.rs", "crates/nu-protocol/src/eval_const.rs", "crates/nu-system/src/lib.rs", "src/main.rs", "src/run.rs"], "root_cause_symbols": [], "supporting_files": ["crates/nu-system/src/process_start.rs"]}, "id": "c40490c94d8d40087ec568af", "metadata": {"confidence": "weak", "created_at": "2026-10-02T14:12:32Z", "evidence": {"implementation_files": ["crates/nu-cli/src/repl.rs", "crates/nu-protocol/src/engine/engine_state.rs", "crates/nu-protocol/src/eval_const.rs", "crates/nu-system/src/lib.rs", "src/main.rs", "src/run.rs"], "related_tests": ["crates/nu-command/tests/commands/exec.rs", "tests/shell/mod.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-02T14:25:12Z", "pr": 19136, "pr_url": "https://github.com/nushell/nushell/pull/19136"}, "query": {"changed_file_summary": "6 implementation files and 2 existing test files changed within 9 total files.", "implementation_file_count": 6, "implementation_files": ["crates/nu-cli/src/repl.rs", "crates/nu-protocol/src/engine/engine_state.rs", "crates/nu-protocol/src/eval_const.rs", "crates/nu-system/src/lib.rs", "src/main.rs", "src/run.rs"], "pr_body": "## Description\n\nThis PR fixes two problems with `$nu.startup-time` reported on Discord.\n\n1. **It grew after every `exec nu`.** While probably more accurate, #19049 counted the time before `main` by reading what the kernel records for the process, but it turned out to be a problem since `exec` replaces the program but keeps the process, so the time would carry over, getting larger with each `exec` which made it no longer correct.\n\n2. **It was `-1ns` in many places.** The value started at `-1` and was only set when the REPL drew its first prompt, or when `-c` commands or a script started running.\n \nSo, I did some research to figure out how other shells, namely bash, zsh, and fish, count startup time.\n\n### How other shells time themselves\n\nNone that I checked reads the process creation time. Each starts its clock inside the shell:\n\n- **bash** sets `shellstart` with `gettimeofday` near the top of `main` (`shell.c`). That is before option parsing and before it takes control of the terminal for job control.\n- **zsh** 5.9 sets `shtimer` with `gettimeofday` in `setupvals()`, after `init_io()` has taken control of the terminal. `$SECONDS` counts from it.\n- **fish** has no startup-time value. `--profile-startup` times each startup command with its own wall clock.\n\nNushell now does the same as bash: the clock starts on the first line of `main` with the monotonic `Instant`. It leaves out the time the OS spends starting the executable, and `exec nu` starts a new count. Like bash, nushell counts the time an interactive `nu &` waits to be brought to the foreground before it can take the terminal; zsh doesn't.\n\n## User-facing changes (Release notes)\n\n### Startup time now starts inside Nushell and is available throughout startup\n\n`$nu.startup-time` is now measured from the start of Nush\n...[truncated]", "pr_title": "fix(startup): time nushell from `main` like bash and zsh, fix `exec`"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "2459fdd134ea4fdbae42efd6924e2b41201cf363", "candidate_corpus": {"base_commit": "2459fdd134ea4fdbae42efd6924e2b41201cf363", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "f48edc35d9dc92bfd2b84ad92a09a965293caaeb", "negative_distractors": ["crates/nu-tui/src/commands/mod.rs", "crates/nu-tui/src/commands/run.rs", "crates/nu-tui/src/commands/table.rs", "crates/nu-tui/src/runtime.rs", "crates/nu-tui/src/session.rs", "crates/nu-tui/src/stream.rs", "crates/nu-tui/src/widget.rs"], "related_tests": ["crates/nu-tui/tests/commands/tui.rs"], "root_cause_files": ["crates/nu-tui/src/app.rs", "crates/nu-tui/src/commands/debug.rs", "crates/nu-tui/src/commands/log.rs", "crates/nu-tui/src/commands/mod.rs", "crates/nu-tui/src/commands/run.rs", "crates/nu-tui/src/commands/table.rs", "crates/nu-tui/src/runtime.rs", "crates/nu-tui/src/session.rs"], "root_cause_symbols": [], "supporting_files": ["crates/nu-tui/src/stream.rs", "crates/nu-tui/src/widget.rs"]}, "id": "907607f1c56441230fe8129c", "metadata": {"confidence": "weak", "created_at": "2026-09-27T21:22:50Z", "evidence": {"implementation_files": ["crates/nu-tui/src/app.rs", "crates/nu-tui/src/commands/debug.rs", "crates/nu-tui/src/commands/log.rs", "crates/nu-tui/src/commands/mod.rs", "crates/nu-tui/src/commands/run.rs", "crates/nu-tui/src/commands/table.rs", "crates/nu-tui/src/runtime.rs", "crates/nu-tui/src/session.rs", "crates/nu-tui/src/stream.rs", "crates/nu-tui/src/widget.rs"], "related_tests": ["crates/nu-tui/tests/commands/tui.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-29T13:30:46Z", "pr": 19099, "pr_url": "https://github.com/nushell/nushell/pull/19099"}, "query": {"changed_file_summary": "10 implementation files and 1 existing test files changed within 11 total files.", "implementation_file_count": 10, "implementation_files": ["crates/nu-tui/src/app.rs", "crates/nu-tui/src/commands/debug.rs", "crates/nu-tui/src/commands/log.rs", "crates/nu-tui/src/commands/mod.rs", "crates/nu-tui/src/commands/run.rs", "crates/nu-tui/src/commands/table.rs", "crates/nu-tui/src/runtime.rs", "crates/nu-tui/src/session.rs"], "pr_body": "## Description\n\n@Bahex reported that `tui` blocked on stream input, \"ranges like `1..` are fine, but just passing it through `each {}` makes tui block. It sometimes works, but if there is a sleep it always blocks.\"\n\nBoth shipped stream examples had this problem:\n\n- `1.. | each {|n| sleep 100ms; $\"tick ($n)\"} | tui label --title \"ticks\" | tui log | tui run` never painted.\n- `1..100 | each {|n| sleep 50ms; $n } | tui progress --total 100 | tui run` painted only after the whole stream had run, so the bar started at 100% and never moved.\n\nThis should be fixed now.\n\n## User-facing changes (Release notes)\n\n### TUI widgets now display streamed data as it arrives\n\nSlow and endless streams now update TUI widgets while `tui run` is open. A log displays each row as it arrives, and a progress bar advances as its input runs instead of starting at 100%:\n\n```nu\n1.. | each {|n| sleep 1sec; $n} | tui log | tui run\n```\n\nThis also works for streams piped into widgets in a child list, such as `tui split [(tail -f app.log | tui log) (ls | tui table)]`.\n\nTUI builders now always output a `tui` value: piping one into a non-TUI command, such as `1.. | tui table | first`, no longer returns the input rows. A TUI value saved with `let` reads its stream on the first run. If the stream finishes, later runs display the same rows; if it stops early, later runs display no rows. When a `tui run` closure, `tui bind`, button, or menu hook returns data, that data replaces the piped data for the rest of the run, without additional rows arriving from the stream.\n\nStreams now keep around 100,000 of their newest rows, dropping older rows in batches of 12,500. Up to 12,499 extra rows can appear between drops, and `tui log --max-lines` can raise the limit further. Piping data into a child list whose widgets all\n...[truncated]", "pr_title": "fix(tui): builders no longer read piped streams, so slow streams show live"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "ac000bbbae917f562a8b7c8602d9853f9d1094e0", "candidate_corpus": {"base_commit": "ac000bbbae917f562a8b7c8602d9853f9d1094e0", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "8ca22347051b92a5818bb859f0867e44f0ae457f", "negative_distractors": [], "related_tests": ["crates/nu-command/tests/commands/path/mod.rs"], "root_cause_files": ["crates/nu-command/src/path/relative_to.rs"], "root_cause_symbols": [], "supporting_files": []}, "id": "e644afafb32e0bc189340b38", "metadata": {"confidence": "weak", "created_at": "2026-09-25T22:28:02Z", "evidence": {"implementation_files": ["crates/nu-command/src/path/relative_to.rs"], "related_tests": ["crates/nu-command/tests/commands/path/mod.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-09T12:40:04Z", "pr": 19089, "pr_url": "https://github.com/nushell/nushell/pull/19089"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["crates/nu-command/src/path/relative_to.rs"], "pr_body": "Disclosure: the code was written by an AI agent (Claude) under my direction; I can't review Rust line-by-line myself.\n\n## Description\n\nIn this PR, I added a `--walk-up` flag to `path relative-to`: when the argument path is not a parent of the input, its leftover components become `..`.\n\n```nu\n> '/a/b/c' | path relative-to '/a/d/e' --walk-up\n../../b/c\n```\n\n- **Opt-in**, as @WindSoilder asked in #14055, following Python's `relative_to(walk_up=True)`. Without the flag, the error still works as an \"is inside\" check (Neovim kept `vim.fs.relpath` parent-only for this reason, neovim/neovim#31790). Spelled `--walk-up` rather than the proposed `--walkup`, to match nu-command's kebab-case flags.\n- **Symlinks** (@sholderbach's question): the command stays lexical and `const`; the help text warns that a symlink in the argument path can make `..` point elsewhere.\n- **Refused with `--walk-up`:** absolute mixed with relative, different Windows drives, and `.` or `..` in the argument after the shared part — none of these can be answered from the text alone.\n- One component walk replaces `strip_prefix` plus the case-insensitive fallback from #16310, so case folding applies to `--walk-up` too. \n- Output without the flag changes in three cases: a leading ./ is ignored ('./a/b' | path relative-to 'a' returns b instead of an error); an absolute input against an empty base is refused ('/a' | path relative-to '' returned /a); and a pair with different roots is refused as \"different roots\" with a hint, instead of \"not a parent\". The error hints at `--walk-up` only when the flag would give a result.\n\nEasier to review commit by commit: the first is a refactor with no behaviour change, the second adds the flag on top of it.\n\n## User-facing changes (Release notes)\n\n`path relative-to` has a new `--\n...[truncated]", "pr_title": "Path relative to walkup"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "fcd35124961bbfb2aeb6947301b1434f1cbafed5", "candidate_corpus": {"base_commit": "fcd35124961bbfb2aeb6947301b1434f1cbafed5", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "01902324611bd3bb51ff22dbd1cba26002f46ba8", "negative_distractors": [], "related_tests": ["crates/nu-command/tests/commands/idx.rs"], "root_cause_files": ["crates/nu-command/src/filesystem/idx/state.rs"], "root_cause_symbols": [], "supporting_files": []}, "id": "dfd3898a4f2dcd3fd45646e8", "metadata": {"confidence": "weak", "created_at": "2026-09-23T16:49:02Z", "evidence": {"implementation_files": ["crates/nu-command/src/filesystem/idx/state.rs"], "related_tests": ["crates/nu-command/tests/commands/idx.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-23T17:55:45Z", "pr": 19078, "pr_url": "https://github.com/nushell/nushell/pull/19078"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["crates/nu-command/src/filesystem/idx/state.rs"], "pr_body": "`idx search` returns at most 200 matches per file, and `--limit` is rounded up to whole files (`--limit 10` returns 200 rows, `--limit 100000` on one file with 1000 matches returns 200).\n\n`stream_grep` builds `GrepSearchOptions` with `..Default::default()`, so FFF's `max_matches_per_file` stays at its default of 200. FFF also only checks `page_limit` after adding all matches of a file, so the result grows in whole-file steps.\n\nThis PR sets `max_matches_per_file` to the requested limit, so a single file can give all requested matches, and truncates the result to `--limit`.\n\n## User-facing changes (Release notes)\n\nFixed `idx search` returning at most 200 matches per file and ignoring the exact `--limit` value.\n\n## Tests + Formatting\n\n- Added `idx_search_limit_is_not_capped_per_file` (250 matches in one file, `--limit 1000` returns 250) and `idx_search_limit_is_exact` (`--limit 10` returns 10). Both fail on `main` with 200 and pass with this change.\n- `cargo test -p nu-command --test tests -- commands::idx::`: 27 passed\n- `cargo fmt --all -- --check`\n- `cargo clippy -p nu-command -- -D warnings -D clippy::unwrap_used`\n\n## Additional notes\n\nFixes #18930", "pr_title": "fix(idx search): don't cap matches at 200 per file"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "9c9f93c7274fffcd3c6ff63736aeeda6ea5bf470", "candidate_corpus": {"base_commit": "9c9f93c7274fffcd3c6ff63736aeeda6ea5bf470", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "356e1c8734d3db7089dd72d6dfe1a8ea96b98b63", "negative_distractors": [], "related_tests": ["crates/nu-command/tests/commands/table/config_matrix.rs", "crates/nu-command/tests/commands/table/themes.rs"], "root_cause_files": ["crates/nu-table/src/common.rs"], "root_cause_symbols": [], "supporting_files": []}, "id": "b538d465282175c849f2962a", "metadata": {"confidence": "weak", "created_at": "2026-09-22T20:31:30Z", "evidence": {"implementation_files": ["crates/nu-table/src/common.rs"], "related_tests": ["crates/nu-command/tests/commands/table/config_matrix.rs", "crates/nu-command/tests/commands/table/themes.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-23T11:57:16Z", "pr": 19066, "pr_url": "https://github.com/nushell/nushell/pull/19066"}, "query": {"changed_file_summary": "1 implementation files and 2 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["crates/nu-table/src/common.rs"], "pr_body": "With `$env.config.table.header_on_separator = true`, the `markdown` and `restructured` themes drew the header inside the top border, which produces invalid markup:\n\n```\n|-#-|-a-|-b-|\n| 0 | 1 | 2 |\n```\n\n```\n=#= =a= =b=\n 0 1 2\n=== === ===\n```\n\nThese two themes exist to emit markup that other tools parse, so as suggested in #13161, `configure_table` now ignores `header_on_separator` for them. Every table goes through `configure_table` (general and `--expand`), so this covers both. Other themes are unchanged.\n\nAfter:\n\n```\n| # | a | b |\n|---|---|---|\n| 0 | 1 | 2 |\n```\n\n`wrap_and_truncate_differ_for_every_theme_with_header_on_separator` (from #18979) no longer lists `markdown` and `restructured`. With the header in its own row, wrapping and truncating give identical output for this data on every theme (e.g. `rounded` with `header_on_separator = false`), because overflowing columns are replaced with `...`. The two only differ in the header-on-border layout, which these themes no longer use.\n\n## User-facing changes (Release notes)\n\n`table --theme markdown` and `table --theme restructured` (and the matching `$env.config.table.mode` values) now always produce valid Markdown / reStructuredText, even when `$env.config.table.header_on_separator` is enabled.\n\n## Tests + Formatting\n\n- Added `table_markup_themes_ignore_header_on_separator`. It fails without this change (`|-#-|-a-|-b-|`) and passes with it.\n- `cargo test -p nu-command --test tests -- commands::table::`: 492 passed\n- `cargo fmt --all -- --check`\n- `cargo clippy -p nu-table -p nu-command --all-targets -- -D warnings -D clippy::unwrap_used`\n\n## Additional notes\n\nFixes #13161", "pr_title": "fix(table): keep markdown and restructured headers off the separator"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "dc1d81a4f03e5f96eb005cceb9abd09f2ffb8186", "candidate_corpus": {"base_commit": "dc1d81a4f03e5f96eb005cceb9abd09f2ffb8186", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "a3af2e300b4f19b11bd795dbedfb8d52ff316edb", "negative_distractors": [], "related_tests": ["crates/nu-command/tests/commands/upsert.rs"], "root_cause_files": ["crates/nu-command/src/filters/flatten.rs"], "root_cause_symbols": [], "supporting_files": []}, "id": "274e192911d909376617311e", "metadata": {"confidence": "weak", "created_at": "2026-09-21T14:28:49Z", "evidence": {"implementation_files": ["crates/nu-command/src/filters/flatten.rs"], "related_tests": ["crates/nu-command/tests/commands/upsert.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-21T15:56:16Z", "pr": 19059, "pr_url": "https://github.com/nushell/nushell/pull/19059"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["crates/nu-command/src/filters/flatten.rs"], "pr_body": "## Description\n\n`flatten` lifts the fields of a nested record up to the top level and, when a lifted field has the same name as an existing top-level column, is supposed to rename it to `_`. That rename only worked in one field order.\n\n```nushell\n# before\n{a: {d: 1}, d: 3} | flatten # => [[d]; [3]] nested d is lost\n{d: 3, a: {d: 1}} | flatten # => [[d, a_d]; [3, 1]] correct\n```\nIn this PR the set is computed unconditionally.\n\n```nushell\n# after\n{a: {d: 1}, d: 3} | flatten # => [[a_d, d]; [1, 3]]\n{d: 3, a: {d: 1}} | flatten # => [[d, a_d]; [3, 1]]\n```\n\n## User-facing changes (Release notes)\n\nFixed an issue where `flatten` silently dropped a nested record field when a top-level column of the same name came later in the record. The nested field is now renamed to `_`, as it already was for the opposite field order. The `flatten` help text now describes how record input is handled.\n\n## Additional notes", "pr_title": "fix(flatten): keep nested fields that collide with top-level columns"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "0667685083650a32d4affc0303584fc1cf20888a", "candidate_corpus": {"base_commit": "0667685083650a32d4affc0303584fc1cf20888a", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "45aa739595bfd51cd28bbc3454f81f1762662a88", "negative_distractors": [], "related_tests": ["crates/nu-command/tests/commands/error_make.rs"], "root_cause_files": ["crates/nu-protocol/src/errors/labeled_error.rs"], "root_cause_symbols": [], "supporting_files": []}, "id": "64a17a6aaaa0aa0a4d07dbf9", "metadata": {"confidence": "weak", "created_at": "2026-09-16T15:40:55Z", "evidence": {"implementation_files": ["crates/nu-protocol/src/errors/labeled_error.rs"], "related_tests": ["crates/nu-command/tests/commands/error_make.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-16T16:24:50Z", "pr": 19037, "pr_url": "https://github.com/nushell/nushell/pull/19037"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["crates/nu-protocol/src/errors/labeled_error.rs"], "pr_body": "## Description\nThe recent changes in #18755 made it so that errors defined with a simple `label: {span: ...}` but no `text` value will cause an error (not the one the user is expecting), when a blank `text` field for a label can be used to simply underline the span. This will still cause an error if `span` is not defined for each label, though.\n\n- Reverts the change in #18755 that removed the default `text: \"\"` value to simply underline labels that only have a span.\n- Maintains the requirement for a `span` in each label\n\n## User-facing changes (Release notes)\n- Adds a default value to `error make`'s labels `text`\n\n## Additional notes\n- Reverts parts of #18755", "pr_title": "error make: Allow no text value"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "7ea33f2510a2b0fb393a6aace644d29d34e6fba6", "candidate_corpus": {"base_commit": "7ea33f2510a2b0fb393a6aace644d29d34e6fba6", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "6b9c094273d14c8346ff22756f29ae48becb07a9", "negative_distractors": [], "related_tests": ["tests/integration/cli.rs"], "root_cause_files": ["src/ide.rs", "src/main.rs"], "root_cause_symbols": [], "supporting_files": []}, "id": "facefb827a8de7152249abb2", "metadata": {"confidence": "weak", "created_at": "2026-09-03T11:37:00Z", "evidence": {"implementation_files": ["src/ide.rs", "src/main.rs"], "related_tests": ["tests/integration/cli.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-03T13:34:16Z", "pr": 18961, "pr_url": "https://github.com/nushell/nushell/pull/18961"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 2, "implementation_files": ["src/ide.rs", "src/main.rs"], "pr_body": "## Description\n\nIn this PR, I fixed an issue where `--ide-check` silently succeeded when the input file could not be read.\n\n`ide::check` previously ignored errors from `std::fs::read(file_path)` by only handling the successful result. The caller then returned `Ok(())`, making missing or unreadable files appear as if no diagnostics were found.\n\nThe check now returns the file read error to the CLI entry point, preserving the existing Nushell I/O error reporting behavior.\n\nFor example:\n\n```text\nnu --ide-check 5 does-not-exist.nu\n```\n\nnow exits with a non-zero status and reports `nu::shell::io::file_not_found`.\n\nA CLI integration test was added for this behavior.\n\n## User-facing changes (Release notes)\n\nFixed an issue where `--ide-check` silently succeeded when the target file could not be read. Nushell now reports the file read error and exits with a non-zero status.\n\n## Additional notes", "pr_title": "ide: report file read failures from --ide-check"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "e19e13d054983d078fe6f658621c417da1a422cd", "candidate_corpus": {"base_commit": "e19e13d054983d078fe6f658621c417da1a422cd", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "07857458b24e71d927f46f9f4bf726fc1e36a9b7", "negative_distractors": [], "related_tests": ["crates/nu-cmd-extra/tests/commands/mod.rs"], "root_cause_files": ["crates/nu-cmd-extra/src/extra/filters/each_while.rs"], "root_cause_symbols": [], "supporting_files": ["crates/nu-cmd-extra/tests/commands/filters/each_while.rs", "crates/nu-cmd-extra/tests/commands/filters/mod.rs"]}, "id": "0df5f2d7d9272a941b667a45", "metadata": {"confidence": "weak", "created_at": "2026-09-02T11:50:17Z", "evidence": {"implementation_files": ["crates/nu-cmd-extra/src/extra/filters/each_while.rs"], "related_tests": ["crates/nu-cmd-extra/tests/commands/mod.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-02T13:20:37Z", "pr": 18958, "pr_url": "https://github.com/nushell/nushell/pull/18958"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 1, "implementation_files": ["crates/nu-cmd-extra/src/extra/filters/each_while.rs"], "pr_body": "## Description\n\n\n\n\nIn this PR, I fixed an issue where `each while` silently treated closure and ByteStream errors as the end of iteration.\n\n`each while` uses `map_while`, where returning `None` means that iteration has finished. The previous implementation converted both closure errors and ByteStream chunk errors into `None`, causing errors to be lost and output to be silently truncated.\n\nThe implementation now preserves these errors as `Value::error`. Only `Value::Nothing` stops iteration.\n\nA regression test covers closure errors:\n\n```nushell\n[1 2 3] | each while {|x|\n if $x == 2 {\n error make {msg: \"boom\"}\n } else {\n $x\n }\n}\n```\n\n\n\n\n## User-facing changes (Release notes)\n\n\nFixed an issue where each while silently stopped when the closure or input ByteStream produced an error. These errors are now preserved and reported.\n\n\n## Additional notes\n\n\nAdded a regression test for closure error handling.", "pr_title": "each while: preserve errors instead of silently stopping"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "f8b4a15a4a3b95a26415316488d34e86ed40399b", "candidate_corpus": {"base_commit": "f8b4a15a4a3b95a26415316488d34e86ed40399b", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "ea229dd2f6d2eaffe6dae6ada1cde96bbfee4797", "negative_distractors": [], "related_tests": ["crates/nu-test-support-macros/Cargo.toml"], "root_cause_files": ["crates/nu-derive-value/src/error.rs", "crates/nu-derive-value/src/lib.rs"], "root_cause_symbols": [], "supporting_files": ["Cargo.lock", "Cargo.toml", "crates/nu-derive-value/Cargo.toml"]}, "id": "6a100d4414340ab25daa3870", "metadata": {"confidence": "weak", "created_at": "2026-08-31T15:43:05Z", "evidence": {"implementation_files": ["crates/nu-derive-value/src/error.rs", "crates/nu-derive-value/src/lib.rs"], "related_tests": ["crates/nu-test-support-macros/Cargo.toml"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-31T16:29:23Z", "pr": 18945, "pr_url": "https://github.com/nushell/nushell/pull/18945"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 6 total files.", "implementation_file_count": 2, "implementation_files": ["crates/nu-derive-value/src/error.rs", "crates/nu-derive-value/src/lib.rs"], "pr_body": "## Description\nThis PR updates proc-macro-error to 3 and some other deps\n\n\n## User-facing changes (Release notes)\n\n\n## Additional notes\ncloses https://github.com/nushell/nushell/issues/18384", "pr_title": "update proc_macro_error to 3 and other dependencies"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "e35265b705a4dfec80bba252a14c5483e63caf5a", "candidate_corpus": {"base_commit": "e35265b705a4dfec80bba252a14c5483e63caf5a", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "fa4263d1293c353a0d0c62483c32da1f4be589ba", "negative_distractors": [], "related_tests": ["tests/integration/cli.rs"], "root_cause_files": ["src/command.rs"], "root_cause_symbols": [], "supporting_files": []}, "id": "ef31d94b50ce1dd8967a07a0", "metadata": {"confidence": "weak", "created_at": "2026-08-25T09:53:43Z", "evidence": {"implementation_files": ["src/command.rs"], "related_tests": ["tests/integration/cli.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-02T12:52:45Z", "pr": 18899, "pr_url": "https://github.com/nushell/nushell/pull/18899"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["src/command.rs"], "pr_body": "## Description\n\nFixes top-level `nu --help` output containing ANSI escape sequences when stdout is redirected.\n\nThe CLI help text is generated before Nushell loads its normal configuration, and the legacy help formatter includes ANSI colors directly. When stdout is not a terminal, this change strips those ANSI sequences immediately before writing the help output.\n\nInteractive terminal output is unchanged and keeps the existing colored help.\n\nCloses #18850.\n\n## User-facing changes\n\n### Redirected `nu --help` output no longer contains ANSI color escapes\n\n`nu --help` no longer writes ANSI escape sequences when its stdout is redirected to a pipe or file.\n\nFor example:\n\n```sh\nnu --help > help.txt\n```\n\nnow produces plain text instead of ANSI-colored text.\n\n## Tests\n\nAdded an integration regression test verifying that `nu --help` invoked with captured stdout contains no ANSI escape byte.\n\nLocal validation:\n\n- `cargo test -p nu --all-features --test tests integration::cli`\n- `cargo test -p nu --all-features --test tests -- --test-threads=1`\n- `cargo clippy -p nu --all-targets --all-features -- -D warnings`\n- `cargo fmt --all -- --check`\n- `git diff --check`\n- manual redirected-output check confirming zero ESC bytes", "pr_title": "fix: strip ANSI from redirected CLI help"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "79690c566710440c019e364869637074721ab483", "candidate_corpus": {"base_commit": "79690c566710440c019e364869637074721ab483", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "1e6f2d2b8b9a9c0a8a5e14ddc82ae2715f7c41df", "negative_distractors": ["crates/nu-command/src/platform/input/legacy_input.rs", "crates/nu-command/src/platform/input/list.rs", "crates/nu-command/src/platform/raw_mode.rs", "crates/nu-command/src/system/run_external.rs", "crates/nu-protocol/src/engine/stack.rs", "crates/nu-system/src/foreground.rs"], "related_tests": ["crates/nu-cli/tests/completions/mod.rs"], "root_cause_files": ["crates/nu-cli/src/completions/completer.rs", "crates/nu-cli/src/menus/menu_completions.rs", "crates/nu-cli/src/util.rs", "crates/nu-command/src/platform/input/legacy_input.rs", "crates/nu-command/src/platform/input/list.rs", "crates/nu-command/src/platform/raw_mode.rs", "crates/nu-command/src/system/run_external.rs", "crates/nu-protocol/src/engine/stack.rs"], "root_cause_symbols": [], "supporting_files": ["crates/nu-system/src/foreground.rs", "crates/nu-config/default_files/doc_config.nu"]}, "id": "a0118a02a56e76d1c1d6fbd2", "metadata": {"confidence": "weak", "created_at": "2026-08-22T14:12:33Z", "evidence": {"implementation_files": ["crates/nu-cli/src/completions/completer.rs", "crates/nu-cli/src/menus/menu_completions.rs", "crates/nu-cli/src/util.rs", "crates/nu-command/src/platform/input/legacy_input.rs", "crates/nu-command/src/platform/input/list.rs", "crates/nu-command/src/platform/raw_mode.rs", "crates/nu-command/src/system/run_external.rs", "crates/nu-protocol/src/engine/stack.rs", "crates/nu-system/src/foreground.rs"], "related_tests": ["crates/nu-cli/tests/completions/mod.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-22T16:32:55Z", "pr": 18881, "pr_url": "https://github.com/nushell/nushell/pull/18881"}, "query": {"changed_file_summary": "9 implementation files and 1 existing test files changed within 11 total files.", "implementation_file_count": 9, "implementation_files": ["crates/nu-cli/src/completions/completer.rs", "crates/nu-cli/src/menus/menu_completions.rs", "crates/nu-cli/src/util.rs", "crates/nu-command/src/platform/input/legacy_input.rs", "crates/nu-command/src/platform/input/list.rs", "crates/nu-command/src/platform/raw_mode.rs", "crates/nu-command/src/system/run_external.rs", "crates/nu-protocol/src/engine/stack.rs"], "pr_body": "## Description\n\nTab completion and custom menus were fighting interactive pickers (`fzf`, `input list`) for the terminal. That is #18879.\n\nTab runs `NuCompleter` on a background worker with `suppress_stdin`. That isolation is right for carapace-style completers that only print a list. It is wrong for a completer that needs the TTY:\n\n- `input list` hit `require_stdin` and declined, so Tab fell back to file completion.\n- `^fzf` with a piped candidate list skipped `setsid`, opened `/dev/tty` on the worker, and raced reedline. The prompt hung after fzf exited.\n\nCtrl+T goes through a menu `source` on the REPL thread, so fzf already worked there. `input list` did not: it always `disable_raw_mode()` on the way out, even when reedline already had raw mode on. Backspace then died inside the same `read_line`.\n\nExternal-arg Tab is now blocking by design whenever a completer closure is configured. That is the same path fzf needs. Call it out in the release notes so Carapace configs are not a surprise.\n\n`ReplTerminalGuard` only restores raw mode after that closure. It does not re-enable bracketed paste or the kitty keyboard protocol. Reedline turns those on at `read_line` start; they are ANSI modes, not termios. Carapace does not touch them. Fzf might. If paste-after-fzf on the same prompt misbehaves, a follow-up should emit `EnableBracketedPaste` / kitty push from the guard using `$env.config.bracketed_paste` and `use_kitty_protocol`.\n\n## User-facing changes (Release notes)\n\n### Interactive pickers in completions\n\nTab completion can run an interactive picker from `$env.config.completions.external.completer` (and from custom `@comp` / `@complete` closures). Closures such as fzf or `input list` take the TTY while the line editor waits. Completers that only print a list should still r\n...[truncated]", "pr_title": "fix(completions): keep the REPL usable when a completer runs `fzf` or `input list`"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "69a2733a00d78ef0d20d30e4704ea2cb30fe1fca", "candidate_corpus": {"base_commit": "69a2733a00d78ef0d20d30e4704ea2cb30fe1fca", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "48d2c58482e9eec4f81dff4d47b2e1528ec544b7", "negative_distractors": ["crates/nu-protocol/src/engine/state_working_set.rs"], "related_tests": ["crates/nu-cli/tests/commands/nu_highlight.rs", "crates/nu-cli/tests/completions/mod.rs", "crates/nu-cli/tests/main.rs"], "root_cause_files": ["crates/nu-cli/src/completions/dotnu_completions.rs", "crates/nu-cli/src/syntax_highlight.rs", "crates/nu-parser/src/parse_module.rs", "crates/nu-protocol/src/engine/state_working_set.rs"], "root_cause_symbols": [], "supporting_files": ["crates/nu-cli/tests/highlight_use.rs"]}, "id": "eb009cd6f52692be2950068d", "metadata": {"confidence": "weak", "created_at": "2026-08-15T15:03:35Z", "evidence": {"implementation_files": ["crates/nu-cli/src/completions/dotnu_completions.rs", "crates/nu-cli/src/syntax_highlight.rs", "crates/nu-parser/src/parse_module.rs", "crates/nu-protocol/src/engine/state_working_set.rs"], "related_tests": ["crates/nu-cli/tests/commands/nu_highlight.rs", "crates/nu-cli/tests/completions/mod.rs", "crates/nu-cli/tests/main.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-25T14:37:45Z", "pr": 18841, "pr_url": "https://github.com/nushell/nushell/pull/18841"}, "query": {"changed_file_summary": "4 implementation files and 3 existing test files changed within 8 total files.", "implementation_file_count": 4, "implementation_files": ["crates/nu-cli/src/completions/dotnu_completions.rs", "crates/nu-cli/src/syntax_highlight.rs", "crates/nu-parser/src/parse_module.rs", "crates/nu-protocol/src/engine/state_working_set.rs"], "pr_body": "## Description\n\nThis PR is intended to be a performance speed-up to help with user experience. When you think about it, the repl is the user interface and so it should be as buttery smooth as possible. This addresses one problem I've seen recently.\n\nTyping `use std/iter` in a debug REPL hitches twice: at the `d` of `std`, and again at `/`. Release builds do the same work; debug just makes it more obvious. The work is on the **paint path**: reedline fully repaints on each key (should fix later), Nushell re-parses the whole line for syntax highlighting, and an open or implicit completion can parse again and walk disk.\n\nThis PR removes those two hitches and two related per-keystroke costs. Execute, `nu-highlight`, and completion of real filesystem modules are unchanged.\n\n## User-facing changes (Release notes)\n\n### Faster typing of `use` in the REPL\n\nThe REPL no longer parse-time-loads a module just to syntax-highlight it. Typing `use std` or `use std/iter` no longer stalls on the first exact match of `std` (most noticeable in debug builds). Execution is unchanged: the module still loads when you run the line.\n\nCompleting `use std/` (and `export use` / `overlay use`) lists virtual standard-library children without walking the current directory. `$NU_LIB_DIRS` is still searched. Completing a real path such as `use ./foo/` is unchanged.\n\nSyntax highlighting also does less work per keystroke: it reuses the last parse of the same line (for example when only the cursor moves) and copies less text while painting.\n\n```nushell\n# These should feel instant to type in the REPL, including debug `cargo run`\nuse std\nuse std/iter\nuse std/assert\n```\n\n## Additional notes", "pr_title": "perf - stop parse-time-loading modules and extra cwd walks while typing `use std/`"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "7ea33f2510a2b0fb393a6aace644d29d34e6fba6", "candidate_corpus": {"base_commit": "7ea33f2510a2b0fb393a6aace644d29d34e6fba6", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "41bc76b1ba34c8297df91ffd9f0f76f4603492ae", "negative_distractors": [], "related_tests": ["crates/nu-parser/tests/test_parser.rs", "tests/repl/test_parser.rs"], "root_cause_files": ["crates/nu-parser/src/parse_calls.rs"], "root_cause_symbols": [], "supporting_files": []}, "id": "a4ee83a40cf66bf066cd802c", "metadata": {"confidence": "weak", "created_at": "2026-08-14T12:46:21Z", "evidence": {"implementation_files": ["crates/nu-parser/src/parse_calls.rs"], "related_tests": ["crates/nu-parser/tests/test_parser.rs", "tests/repl/test_parser.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-03T13:02:32Z", "pr": 18837, "pr_url": "https://github.com/nushell/nushell/pull/18837"}, "query": {"changed_file_summary": "1 implementation files and 2 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["crates/nu-parser/src/parse_calls.rs"], "pr_body": "## Description\nExternal command arguments are normally parsed as strings. This caused closures such as `{|x| $\"($x)\" }` to be treated as interpolated strings, placing closure parameters outside their intended scope and producing a misleading `variable_not_found` error.\n\nExternal arguments beginning with `{` now use Nushell’s existing `parse_brace_expr` logic. This consistently supports:\n - Parameterized closures such as `{|x| ...}`\n - Parameterized closures with whitespace such as `{ |x| ...}`\n - Parameterless closures such as `{ ... }`\n - Records such as `{a: 1}`\n - Empty records such as `{}`\n\nBecause unquoted brace expressions are now parsed as Nushell values, braces intended as literal external arguments must be quoted:\n\n```nu\n^some-command '{a:1}'\n```\nTests cover parameterized and parameterless closures, records, empty records, and quoted record-like strings.\n\n## User-facing changes (Release notes)\n\nExternal command arguments beginning with { are now parsed as closures or records; literal curly-braced arguments must be quoted.\n\n## Additional notes\nCloses #18116", "pr_title": "fix(parser): parse brace expressions in external calls"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "7b16832813dcd6482b30e5363f0b703998fcc610", "candidate_corpus": {"base_commit": "7b16832813dcd6482b30e5363f0b703998fcc610", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "cad45395e147c68d500ac9cee980eb7e42211232", "negative_distractors": ["crates/nu-command/src/filters/default.rs", "crates/nu-engine/src/compile/builder.rs", "crates/nu-engine/src/compile/call.rs", "crates/nu-engine/src/compile/expression.rs", "crates/nu-engine/src/compile/keyword.rs", "crates/nu-engine/src/compile/operator.rs", "crates/nu-engine/src/eval_ir.rs", "crates/nu-protocol/src/ir/display.rs"], "related_tests": ["crates/nu-command/tests/requires_ast_for_arguments.rs"], "root_cause_files": ["crates/nu-cmd-lang/src/core_commands/attr/example.rs", "crates/nu-command/src/debug/metadata.rs", "crates/nu-command/src/env/export_env.rs", "crates/nu-command/src/filters/default.rs", "crates/nu-engine/src/compile/builder.rs", "crates/nu-engine/src/compile/call.rs", "crates/nu-engine/src/compile/expression.rs", "crates/nu-engine/src/compile/keyword.rs"], "root_cause_symbols": [], "supporting_files": ["crates/nu-engine/src/compile/operator.rs", "crates/nu-engine/src/eval_ir.rs", "crates/nu-protocol/src/ir/display.rs", "crates/nu-protocol/src/ir/mod.rs"]}, "id": "4c085a1e0a6557227cc1c8e8", "metadata": {"confidence": "weak", "created_at": "2026-08-10T19:01:41Z", "evidence": {"implementation_files": ["crates/nu-cmd-lang/src/core_commands/attr/example.rs", "crates/nu-command/src/debug/metadata.rs", "crates/nu-command/src/env/export_env.rs", "crates/nu-command/src/filters/default.rs", "crates/nu-engine/src/compile/builder.rs", "crates/nu-engine/src/compile/call.rs", "crates/nu-engine/src/compile/expression.rs", "crates/nu-engine/src/compile/keyword.rs", "crates/nu-engine/src/compile/operator.rs", "crates/nu-engine/src/eval_ir.rs", "crates/nu-protocol/src/ir/display.rs", "crates/nu-protocol/src/ir/mod.rs"], "related_tests": ["crates/nu-command/tests/requires_ast_for_arguments.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-25T14:37:16Z", "pr": 18813, "pr_url": "https://github.com/nushell/nushell/pull/18813"}, "query": {"changed_file_summary": "12 implementation files and 1 existing test files changed within 13 total files.", "implementation_file_count": 12, "implementation_files": ["crates/nu-cmd-lang/src/core_commands/attr/example.rs", "crates/nu-command/src/debug/metadata.rs", "crates/nu-command/src/env/export_env.rs", "crates/nu-command/src/filters/default.rs", "crates/nu-engine/src/compile/builder.rs", "crates/nu-engine/src/compile/call.rs", "crates/nu-engine/src/compile/expression.rs", "crates/nu-engine/src/compile/keyword.rs"], "pr_body": "## Description\n\nRuntime block evaluation has been IR-only for a long time (`eval_block` → `eval_ir_block`). Some commands still forced the IR compiler to retain full argument **AST** nodes via `Command::requires_ast_for_arguments()`, which is expensive and blocks collapsing the dual `engine::Call` / `CallImpl::{Ast*, Ir*}` surface.\n\nThis PR finishes **phases 0 and 1** of the IR-only **call** migration:\n\n- Removes every remaining `requires_ast_for_arguments` override.\n- Adds a regression inventory test so new opt-ins are deliberate.\n- Redesigns the last AST-arg consumers so they work from evaluated values / IR special cases.\n\nParser AST is **not** removed. It remains the compile-time intermediate (parse → AST → IR → VM). The goal is IR-only **command invocation**, not “delete the AST.”\n\nSeveral commands still opted into `requires_ast_for_arguments`, forcing the compiler to retain full argument AST nodes under IR. This PR removes all of those opt-ins (phases 0–1):\n\n- **Phase 0:** drop unused `timeit` flag; treat `unlet` as IR-only (`compile_unlet` + stubbed `run`); add inventory test; document the plan.\n- **Phase 1:** redesign remaining consumers:\n - `export-env` — evaluated `Closure` / block id\n - `metadata` — value-only run + `LoadVariable { preserve_origin }` for bare vars; stop re-stamping spans on `PushPositional` / `AppendRest`\n - `default` — deprecation warning via span source starting with `$`\n - `attr example` — runtime without AST; const still uses AST call for block source until phase 2 (const closures / IR-shaped `run_const`)\n\n## User-facing changes (Release notes)\n\n- None expected for normal scripts.\n- Internal: IR `load-variable` may show as `load-variable-origin` when preserving definition spans for `metadata $var`.\n- `default $closure_var` deprecation\n...[truncated]", "pr_title": "reduce ast dependency for ir calls - phase 1"}, "query_provenance": "pr_summary", "repo": "nushell/nushell", "task_type": "code2test", "version": 2} +{"base_commit": "b500a2ee95134f81d74da7911d7378dd2853d042", "candidate_corpus": {"base_commit": "b500a2ee95134f81d74da7911d7378dd2853d042", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "680d19f7d1e042e55934209caeb79bc843b94f44", "negative_distractors": [], "related_tests": ["packages/zod/src/v4/classic/tests/union.test.ts"], "root_cause_files": ["packages/zod/src/v4/core/schemas.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "2187f285b768b1ac9366946d", "metadata": {"confidence": "weak", "created_at": "2026-10-12T18:22:58Z", "evidence": {"implementation_files": ["packages/zod/src/v4/core/schemas.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/union.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-13T18:16:29Z", "pr": 6662, "pr_url": "https://github.com/colinhacks/zod/pull/6662"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["packages/zod/src/v4/core/schemas.ts"], "pr_body": "A union reports an option's own issues again when a size bound was the only thing that rejected it. Since #6652, `.max()`, `.length()` and `.size()` reject an oversized array, set or map before its elements are parsed. That issue aborts so no later check reads the unparsed value, and the union read the abort as a type mismatch and fell back to `invalid_union`.\n\n```ts\nz.union([z.array(z.string()).max(2), z.string()]).safeParse([\"a\", \"b\", \"c\"]);\n// 4.6.5 and now: too_big from the array option\n// 4.6.6: invalid_union\n```\n\nThe abort in the size check stays. Instead, when no option can continue, the union now falls back to the options whose issues all came from checks, and reports that option when it is the only one. This reads the `continue` flag every issue already carries: `true` or `false` when a check raised it, unset when the type didn't match.\n\nThis only ever turns an `invalid_union` into a single option's issues. Every case that already reported one option still does. Besides the regression, a few other options that a check stopped outright are now reported directly, where they used to give `invalid_union`:\n\n- `z.int()`: `z.union([z.int(), z.string()]).safeParse(1.5)` now reports \"expected int, received number\".\n- An option rejected by `.refine(..., { abort: true })` or a `fatal: true` issue now reports that issue.\n\n| axis | result |\n| --- | --- |\n| runtime | Only reached when every option fails. When all of them fail on type, ~4–5% slower (1033 → 1078 ns median, 6 interleaved rounds). The capped case is 2.3x faster since it no longer builds `invalid_union`. Successful parses are unchanged. |\n| memory | Unchanged. Nothing is added to schema instances. |\n| bundle | `zod/mini` union fixture +26 B gzipped (3778 → 3804, +0.7%), classic +28 B (+0.1%). Bundles without a un\n...[truncated]", "pr_title": "fix(v4): report a union option that only checks rejected"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "b500a2ee95134f81d74da7911d7378dd2853d042", "candidate_corpus": {"base_commit": "b500a2ee95134f81d74da7911d7378dd2853d042", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "40a5dba080b065cc430e5b0e64a8058d68c1660d", "negative_distractors": ["packages/zod/src/v4/locales/hr.ts", "packages/zod/src/v4/locales/lt.ts"], "related_tests": ["packages/zod/src/v4/core/tests/locales/he.test.ts", "packages/zod/src/v4/core/tests/locales/parity.test.ts"], "root_cause_files": ["packages/zod/src/v4/locales/es.ts", "packages/zod/src/v4/locales/fr.ts", "packages/zod/src/v4/locales/he.ts", "packages/zod/src/v4/locales/hr.ts", "packages/zod/src/v4/locales/lt.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "1bffb30519d65c8252b17919", "metadata": {"confidence": "weak", "created_at": "2026-10-12T18:21:02Z", "evidence": {"implementation_files": ["packages/zod/src/v4/locales/es.ts", "packages/zod/src/v4/locales/fr.ts", "packages/zod/src/v4/locales/he.ts", "packages/zod/src/v4/locales/hr.ts", "packages/zod/src/v4/locales/lt.ts"], "related_tests": ["packages/zod/src/v4/core/tests/locales/he.test.ts", "packages/zod/src/v4/core/tests/locales/parity.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-13T18:15:58Z", "pr": 6661, "pr_url": "https://github.com/colinhacks/zod/pull/6661"}, "query": {"changed_file_summary": "5 implementation files and 2 existing test files changed within 7 total files.", "implementation_file_count": 5, "implementation_files": ["packages/zod/src/v4/locales/es.ts", "packages/zod/src/v4/locales/fr.ts", "packages/zod/src/v4/locales/he.ts", "packages/zod/src/v4/locales/hr.ts", "packages/zod/src/v4/locales/lt.ts"], "pr_body": "Fixes #6657.\n\n`es`, `fr`, `he`, `hr` and `lt` had no `map` entry in `Sizable`, so `z.map()` size errors dropped their unit (`se esperaba que mapa fuera <=1`, and `lt` appended `undefined`). Each now copies its `set` entry, the same convention #6427 used. Hebrew also routes maps through its array/set phrasing (\"should contain N items\"), taking the verb's gender from its type table.\n\n#6427 touched all five files and added a parity test for exactly this, which passed anyway: its sentinel probe only sees a gap when a locale's size fallback echoes the raw origin, and these five render it as a translated noun (`mapa`), a placeholder (`valeur`), a capitalized word, or a label-table entry. `Sizable` is now checked against each locale's source instead; the `FormatDictionary` probe is unchanged, since every locale echoes an unknown format. Run against the old locale files, the new check reports exactly these five.\n\nThe `lt` trailing `undefined` for number, bigint and date (#6655) is a separate fix.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)", "pr_title": "fix(locales): add Sizable.map to es, fr, he, hr and lt, and check Sizable parity from source"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "b500a2ee95134f81d74da7911d7378dd2853d042", "candidate_corpus": {"base_commit": "b500a2ee95134f81d74da7911d7378dd2853d042", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "311cd74b2765ff7c7b58add60e37c5a0ea7a1972", "negative_distractors": [], "related_tests": ["packages/zod/src/v4/classic/tests/record.test.ts", "packages/zod/src/v4/core/tests/compile.test.ts"], "root_cause_files": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/schemas.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "80cc91a82ca32528d464e514", "metadata": {"confidence": "weak", "created_at": "2026-10-12T17:57:46Z", "evidence": {"implementation_files": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/schemas.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/record.test.ts", "packages/zod/src/v4/core/tests/compile.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-13T18:15:16Z", "pr": 6660, "pr_url": "https://github.com/colinhacks/zod/pull/6660"}, "query": {"changed_file_summary": "2 implementation files and 2 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/schemas.ts"], "pr_body": "Fixes #6641.\n\nA record whose key schema is a constraint — a refine, a regex, a `z.partialRecord` enum — skipped an own `__proto__` input key before the key schema ran, so a JSON body carrying `__proto__` passed records that reject every other bad key. The key now goes through the key schema like any other and is reported as `invalid_key` (or `unrecognized_keys` for a partial enum) when it fails. It is still never written to the output, even when the key schema accepts or renames it, so the stripping from #6386 is unchanged. This matches `.strict()` since #6221 and the exhaustive `z.record(z.enum())` path, which already reported it.\n\nThe compiled path gets the same change, and a loose record still drops the key rather than passing it through. Bundle size and record parse throughput are unchanged within noise.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)", "pr_title": "fix(v4): run a record's key schema on an own __proto__ key"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "0b216ef674e297ebe41d8bf902262e56f8755822", "candidate_corpus": {"base_commit": "0b216ef674e297ebe41d8bf902262e56f8755822", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "e06a510b6fc1e6e28e3201fd116ca2a76212f6be", "negative_distractors": [], "related_tests": ["packages/zod/src/v4/classic/tests/array.test.ts", "packages/zod/src/v4/classic/tests/map.test.ts", "packages/zod/src/v4/classic/tests/set.test.ts"], "root_cause_files": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/util.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "05fbf612721ae8ce92034708", "metadata": {"confidence": "weak", "created_at": "2026-10-07T16:21:53Z", "evidence": {"implementation_files": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/util.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/array.test.ts", "packages/zod/src/v4/classic/tests/map.test.ts", "packages/zod/src/v4/classic/tests/set.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-09T19:50:22Z", "pr": 6652, "pr_url": "https://github.com/colinhacks/zod/pull/6652"}, "query": {"changed_file_summary": "3 implementation files and 3 existing test files changed within 6 total files.", "implementation_file_count": 3, "implementation_files": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/util.ts"], "pr_body": "`.max()`, `.length()` and `.size()` on arrays, sets and maps now reject an oversized input before any element is parsed. The bound used to run after the walk, so it bounded nothing: `z.array(z.string().uuid()).max(100)` given a million numbers built 1,000,001 issues before it reported `too_big`.\n\n```ts\nz.array(z.string().uuid()).max(100).safeParse(Array(1_000_000).fill(0));\n// one too_big issue in under a millisecond, was 1,000,001 issues in ~450 ms\n```\n\nOnly size checks that come before every other check take part, since something like `.overwrite()` can shrink the value first. The early rejection aborts, so a later `.refine()` never sees elements that weren't parsed, and an oversized input reports just the `too_big` issue rather than its element issues too. The compiled path gets the same check ahead of its loop. Unbounded containers are unchanged.\n\n| axis | result |\n| --- | --- |\n| runtime | The check wraps `parse` only on schemas that carry an upper bound, so an unbounded container runs the same code as before. `z.array(z.string()).max(100)` over 10 items: 65.9 → 67.4 ns (+1–3%, interleaved, but taken at load 10–20). Construction within noise. |\n| memory | Unbounded: unchanged. Bounded: +121 B per schema (3421 → 3542) for the wrapper closure. |\n| bundle | `zod/mini` array fixture +243 B gzipped (3311 → 3554, +7.3%), +227 with a `maxLength` check. Classic array +215 (+1.0%). Bundles without an array, set or map pay nothing (`zod-mini-object` unchanged). |\n\nPutting the check inside the existing parse closure was smaller (~190 B) but pushed it past V8's inlining budget: `z.array(z.string()).max(n)` parses went 58 → 71 ns.\n\nFixes #6643", "pr_title": "fix(v4): check array, set and map size bounds before parsing elements"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "d2b135cfb7a3582b9eb515756b9166bcb9521f4a", "candidate_corpus": {"base_commit": "d2b135cfb7a3582b9eb515756b9166bcb9521f4a", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "56222cd1532c07bcb91b67df529cab4c0a215330", "negative_distractors": [], "related_tests": ["packages/zod/src/v4/classic/tests/properties.test.ts"], "root_cause_files": ["packages/zod/src/v4/classic/schemas.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "b2abf079c95d87996b1402db", "metadata": {"confidence": "weak", "created_at": "2026-09-13T18:25:35Z", "evidence": {"implementation_files": ["packages/zod/src/v4/classic/schemas.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/properties.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-13T18:30:47Z", "pr": 6600, "pr_url": "https://github.com/colinhacks/zod/pull/6600"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["packages/zod/src/v4/classic/schemas.ts"], "pr_body": "The method took any `$ZodShape`, so `z.instanceof(File).properties({ nmae: z.string() })` compiled, and so did a schema that can't accept the property's type. The shape is now a mapped type over `keyof T`, so the keys autocomplete and both of those are errors.\n\nMethods are excluded from the shape, which was the one real obstacle here. Every object literal inherits `Object.prototype.toString`, so a constraint carrying `URL`'s own `toString` entry rejects every shape literal passed to it.\n\nType-only — the emitted JS is byte-identical, so runtime, memory and bundle are all unchanged and only the `.d.ts` grows. It does tighten a public signature: a shape key outside the instance type, or on a method, now fails to compile where it previously didn't.\n\nOn the Zod Mini side: the spread form already rejects an unknown key and a wrong property type in both builds, since the check's input type demands the properties exist on the base. What it doesn't get is autocomplete, because the shape literal is written before any contextual type reaches it. That would need either a new exported helper, which costs bytes in every mini bundle, or a change to the shared `.check()` signature.\n\nRefs #6598", "pr_title": "feat(instanceof): key the .properties() shape off the instance type"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "1c51cbe0fe23d09f8d520b31487d50a01588fae5", "candidate_corpus": {"base_commit": "1c51cbe0fe23d09f8d520b31487d50a01588fae5", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "b12aa523e7e2617c4296cccf9b24d6558ed23e95", "negative_distractors": [], "related_tests": ["packages/zod/src/v4/classic/tests/discriminated-unions.test.ts"], "root_cause_files": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/schemas.ts"], "root_cause_symbols": [], "supporting_files": ["packages/docs/content/api.mdx"]}, "id": "7590a493f644f3e4099dbfc7", "metadata": {"confidence": "weak", "created_at": "2026-09-09T17:44:01Z", "evidence": {"implementation_files": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/schemas.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/discriminated-unions.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-09T19:20:34Z", "pr": 6582, "pr_url": "https://github.com/colinhacks/zod/pull/6582"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/schemas.ts"], "pr_body": "Preserve explicitly tagged parsing when multiple discriminated-union members have defaulted tags. A shared map builder marks colliding `undefined` values as ambiguous; missing tags fail validation, while unique tags retain direct dispatch. Other duplicate values remain schema errors.\n\nThere are no schema-type checks, wrapper walks, new options, or new instance properties. The lookup helper uses the same map builder and rejects ambiguous lookup. Nested unions omit an unroutable `undefined` from their discriminator metadata; backward encoding of `undefined` uses the existing union fallback so forward-only metadata cannot select the wrong sibling. Defined tags retain their encoding fast path. The compiler keeps its existing interpreter fallback for collisions rather than introducing a second dispatch policy.\n\nLocal build, lint, resolution, integration, and the full suite pass, including 8,243 tests on each of TypeScript 5.5.4, 6.0.3, and 7.0.2. Plain-Node ESM/CJS probes pass for both classic and Mini. The encoding regression has synchronous and asynchronous coverage, and the API reference documents ambiguous lookup.\n\n| Measurement | Base → change |\n| --- | --- |\n| Parse, median of ten process minima | 38.06 → 38.44 ns (+1.0%) |\n| Defined-tag encode, median of ten process minima | 48.21 → 48.03 ns (-0.4%) |\n| Construction, median of ten process minima | 802.6 → 804.1 ns (+0.2%) |\n| Classic discriminated-union fixture, gzip | 21,159 → 21,248 B (+89 B) |\n| Mini discriminated-union fixture, gzip | 5,238 → 5,339 B (+101 B) |\n| Classic / Mini object-only fixtures | unchanged |\n| Fresh two-member union, retained heap | 9,136 → 9,136 B in repeated isolated measurements |\n| Shared-member union, unparsed / parsed | approximately 921 / 1,098 B on both revisions |\n\nRuntime measurement\n...[truncated]", "pr_title": "fix: preserve unique tags with defaulted discriminators"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "36f17960d1defca5d0896d9424f4e1059fbbf081", "candidate_corpus": {"base_commit": "36f17960d1defca5d0896d9424f4e1059fbbf081", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "213ee75d2ad6e41508587c3fab8246967f006993", "negative_distractors": [], "related_tests": ["packages/zod/src/v4/core/tests/compile.test.ts"], "root_cause_files": ["packages/zod/src/v4/classic/external.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/mini/external.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "203974360ae14463a3cf0b31", "metadata": {"confidence": "weak", "created_at": "2026-09-09T05:16:08Z", "evidence": {"implementation_files": ["packages/zod/src/v4/classic/external.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/mini/external.ts"], "related_tests": ["packages/zod/src/v4/core/tests/compile.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-09T16:31:49Z", "pr": 6575, "pr_url": "https://github.com/colinhacks/zod/pull/6575"}, "query": {"changed_file_summary": "3 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 3, "implementation_files": ["packages/zod/src/v4/classic/external.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/mini/external.ts"], "pr_body": "Exports `z.withParser(schema, parser)` — the installer half of `compile()`, so a build-time or native compiler can supply the parser where `new Function` isn't available. `compile()` calls it, so the wrapper contract has one implementation.\n\nThe parser returns the parsed value or `INVALID`, which is now exported too. Zod keeps everything else: the clone, the async/backward/skip-check bypasses, the memoizer back-edge check, the fallback flag, and the runtime as the only source of `ZodError`s.\n\nTwo design calls worth flagging.\n\nA supplied parser is its own validator rather than getting a generated assert-only one. Reaching `compileValidator` pulls `compileFn` and the whole codegen into any bundle that imports `withParser` — measured at +7.4 KB gz on a classic fixture. It's also the better semantic: one implementation means `parse()` and `validate()` can't disagree, and an undefined `definite` keeps `validate`'s runtime re-parse on every rejection.\n\nThe recursion guard moves with the installer. A supplied parser skips `compileFn`, which is what refuses a schema whose subtree contains a cycle; generated code never receives the parse context, so only the runtime can close one. `isRecursiveSchema` needs no eval, so it runs on this path too.\n\nThree axes: parse-path runtime unchanged (the wrapper is byte-identical), construction +0.03% from the added structural walk (0.02 µs against 60.74 µs for a full `z.compile`), memory unchanged (same three fields on the bag), bundle −2 B gz on both `zod-object` and `zod-mini-object` fixtures — non-users pay nothing, and `withParser` alone bundles to 1.4 KB gz.\n\nRefs #6498.", "pr_title": "feat(compile): add z.withParser for externally generated parsers"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "804e0f522747345d6b37581888899be420baa3e9", "candidate_corpus": {"base_commit": "804e0f522747345d6b37581888899be420baa3e9", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "741981ffdbc8772cffc38cc4eaf84d5a45fa7384", "negative_distractors": ["packages/zod/src/v4/core/errors.ts", "packages/zod/src/v4/core/util.ts"], "related_tests": ["packages/treeshake/bundle-size.test.ts", "packages/zod/src/v4/classic/tests/error.test.ts", "packages/zod/src/v4/core/tests/compile.test.ts"], "root_cause_files": ["packages/bench/error-construction-breakdown.ts", "packages/bench/memory/compiled-slope.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/errors.ts", "packages/zod/src/v4/core/util.ts"], "root_cause_symbols": [], "supporting_files": ["packages/zod/src/v4/core/tests/compile-generative.test.ts"]}, "id": "94ced9a3405cdf38385a8926", "metadata": {"confidence": "weak", "created_at": "2026-09-08T02:47:06Z", "evidence": {"implementation_files": ["packages/bench/error-construction-breakdown.ts", "packages/bench/memory/compiled-slope.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/errors.ts", "packages/zod/src/v4/core/util.ts"], "related_tests": ["packages/treeshake/bundle-size.test.ts", "packages/zod/src/v4/classic/tests/error.test.ts", "packages/zod/src/v4/core/tests/compile.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-08T19:33:03Z", "pr": 6567, "pr_url": "https://github.com/colinhacks/zod/pull/6567"}, "query": {"changed_file_summary": "5 implementation files and 3 existing test files changed within 9 total files.", "implementation_file_count": 5, "implementation_files": ["packages/bench/error-construction-breakdown.ts", "packages/bench/memory/compiled-slope.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/errors.ts", "packages/zod/src/v4/core/util.ts"], "pr_body": "The mode-independent half of #6559, which I'm closing in favor of this. `z.compile` keeps today's runtime re-parse on invalid input; what lands here is the part of that branch that helps regardless of how issues get built.\n\n**Record fast path.** The compiled record walked keys through `Reflect.ownKeys` with a `propertyIsEnumerable` call per key, 154 ns on two keys before any value was checked. It now snapshots the string keys with `getOwnPropertyNames` and the symbol keys with `getOwnPropertySymbols` before any value is read, and rechecks each key's enumerability when it is visited, which is the runtime's `Reflect.ownKeys` walk exactly, order included: a getter that adds, deletes, hides or reveals a key mid-walk gets the runtime's verdict. Pullfrog took two cheaper snapshots off the table on the way here (for-in enumerates the prototype chain after the own keys, `Object.keys` drops a key that is non-enumerable at snapshot time) and both are pinned. Two valid keys 259 → ~106 ns against the interpreter's 214, ten keys 971 → ~496 against 864. A proxy input sees two `ownKeys` traps instead of the interpreter's one; that is the one accepted difference.\n\n**Cheaper issue finalization.** `finalizeIssue` copies the raw issue's own keys with a loop over `Object.keys` instead of object rest with excluded keys, which V8 routes through a generic runtime call (175 → 147 ns in-process; a for-in walk was faster still but also copied inherited enumerable keys off an issue pushed as a class instance, which Copilot caught). Two deliberate differences from object rest: an own `__proto__` key on a raw issue, as `JSON.parse` produces, is dropped rather than assigned through the setter, the same as the record walk already does; and own symbol-keyed fields are not copied, since nothing in zod\n...[truncated]", "pr_title": "perf(compile): for-in record walk, cheaper issue finalization, and a generative compile differential"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "cafbee4772ef481611fef6f5fb9ed9a1b9597069", "candidate_corpus": {"base_commit": "cafbee4772ef481611fef6f5fb9ed9a1b9597069", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "62e6624bc72c4882968ac4ea2c4281b1a99a7ad4", "negative_distractors": [], "related_tests": ["packages/zod/src/v4/classic/tests/validate.test.ts"], "root_cause_files": ["packages/zod/src/v4/classic/schemas.ts"], "root_cause_symbols": [], "supporting_files": ["packages/docs/content/basics.mdx"]}, "id": "a5642eafa189219dc20d6979", "metadata": {"confidence": "weak", "created_at": "2026-09-01T19:20:07Z", "evidence": {"implementation_files": ["packages/zod/src/v4/classic/schemas.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/validate.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-01T20:18:21Z", "pr": 6547, "pr_url": "https://github.com/colinhacks/zod/pull/6547"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["packages/zod/src/v4/classic/schemas.ts"], "pr_body": "`z.validate()` and `z.validateAsync()` shipped in 4.5 as top-level functions only. Classic reaches for methods everywhere else, so this adds `.validate()` and `.validateAsync()` to `ZodType` as thin delegates.\n\n```ts\nconst Player = z.object({ username: z.string(), xp: z.number() });\n\nif (Player.validate(data)) {\n data.username; // narrowed\n}\n```\n\nThe predicate lives on the interface, not in the member table — `util.ProtoOf` maps a type-predicate signature's `infer R` to plain `boolean`, so the implementation needs no cast. Narrowing goes to the schema's **input** type: `z.string().transform(s => s.length).validate(v)` narrows `v` to `string`, never `number`.\n\n`zod/mini` deliberately does not get these. It stays a top-level-function API, and a test pins that.\n\n## Three axes\n\n**Bundle** — the one that got worse. esbuild `--minify --conditions=@zod/source`, gzip -9, against a pristine `origin/main` worktree:\n\n| fixture | main | branch | delta |\n| --- | --- | --- | --- |\n| `zod-mini-boolean` / `-string` / `-object` / `-simple-object` / `-full` | — | — | **+0** |\n| `zod-boolean` | 17003 | 17177 | +174 |\n| `zod-string` | 21035 | 21224 | +189 |\n| `zod-object` | 25113 | 25288 | +175 |\n| `zod-full` | 25106 | 25286 | +180 |\n| `zod-named-import` | 89192 | 89220 | +28 |\n\nA prototype reference to `parse.validate` retains the validate implementation that a tree-shaken classic bundle used to drop; `zod.compile.fallback` and `zod.compile.invalid` go from absent to present. That is the same trade `encode`/`decode` already make, and it is unavoidable for a method form. `zod/mini` is byte-identical on every fixture, which is the line that matters most on this axis. The `packages/treeshake` ceilings cover mini only, so none needed raising.\n\n**Memory** — no change, and this one is struc\n...[truncated]", "pr_title": "feat(v4): add .validate() and .validateAsync() to Zod Classic"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "07917f4cb396646dff7a1364f9032a668b0d7eb4", "candidate_corpus": {"base_commit": "07917f4cb396646dff7a1364f9032a668b0d7eb4", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "764ac59f1afc1a46e7ecc2d5e8e86c57b7d66164", "negative_distractors": [], "related_tests": ["packages/treeshake/bundle-size.test.ts", "packages/zod/src/v4/classic/tests/validate.test.ts"], "root_cause_files": ["packages/bench/validate-abort-sweep.ts", "packages/zod/src/v4/core/parse.ts", "packages/zod/src/v4/core/schemas.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "cb9149251d5adbd407c2b8be", "metadata": {"confidence": "weak", "created_at": "2026-09-01T03:28:17Z", "evidence": {"implementation_files": ["packages/bench/validate-abort-sweep.ts", "packages/zod/src/v4/core/parse.ts", "packages/zod/src/v4/core/schemas.ts"], "related_tests": ["packages/treeshake/bundle-size.test.ts", "packages/zod/src/v4/classic/tests/validate.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-01T22:04:37Z", "pr": 6544, "pr_url": "https://github.com/colinhacks/zod/pull/6544"}, "query": {"changed_file_summary": "3 implementation files and 2 existing test files changed within 5 total files.", "implementation_file_count": 3, "implementation_files": ["packages/bench/validate-abort-sweep.ts", "packages/zod/src/v4/core/parse.ts", "packages/zod/src/v4/core/schemas.ts"], "pr_body": "Today `z.validate()` walks the whole schema even after the answer is settled. On a 20-key object with a wrong value in the first key, it still parses the other 19 — the boolean was decided at key 0, and everything after it is work nobody reads.\n\nThis gives the runtime parse path an early exit and lets `validate` / `validateAsync` take it. Nothing else does, and there is no new public surface: the context field is internal, and the commented-out `abortEarly` on the public `ParseContext` stays commented out.\n\nThe asymmetry is what makes it safe. Reporting every issue and handing back a well-formed value is what `safeParse` owes its caller, so it can never stop early. A boolean is all `validate` returns, so the truncated value a stopped container leaves behind is never read by anyone.\n\n### The contract\n\nFirst failure in parse order wins. Once an aborting issue settles the boolean, the container stops before the next child it would have parsed, so a callback there never runs — exactly as if it were not in the schema:\n\n```ts\nconst schema = z.object({\n a: z.number(),\n b: z.string().transform(() => { throw new RangeError(); }),\n});\nschema.safeParse({ a: \"bad\", b: \"ok\" }); // throws: it walks the whole shape\nz.validate(schema, { a: \"bad\", b: \"ok\" }); // false: `a` settled it, `b` never ran\n```\n\nA throw that does happen still bubbles, unchanged. Nothing rejects before the callback below, so `validate` runs it and the exception is the caller's:\n\n```ts\nz.validate(z.object({ a: z.string().transform(boom), b: z.number() }), { a: \"ok\", b: \"bad\" }); // throws\n```\n\nThe stop lands between children, never inside one. A map entry parses its key and value together, and a tuple runs every fixed item before `handleTupleResults` decides which issues survive — so neither can skip the other\n...[truncated]", "pr_title": "perf(v4): settle z.validate on the first failure in parse order"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "18e71c71daff6e79ab8f00a48db252ccb340da1f", "candidate_corpus": {"base_commit": "18e71c71daff6e79ab8f00a48db252ccb340da1f", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "90269c601aae25499ee87e78a07508564825867f", "negative_distractors": [], "related_tests": ["packages/zod/src/v4/classic/tests/enum.test.ts", "packages/zod/src/v4/mini/tests/index.test.ts"], "root_cause_files": ["packages/zod/src/v4/classic/schemas.ts", "packages/zod/src/v4/mini/schemas.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "1ce18187486c684e2d7e1bc6", "metadata": {"confidence": "weak", "created_at": "2026-08-31T23:18:23Z", "evidence": {"implementation_files": ["packages/zod/src/v4/classic/schemas.ts", "packages/zod/src/v4/mini/schemas.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/enum.test.ts", "packages/zod/src/v4/mini/tests/index.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-31T23:27:00Z", "pr": 6542, "pr_url": "https://github.com/colinhacks/zod/pull/6542"}, "query": {"changed_file_summary": "2 implementation files and 2 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["packages/zod/src/v4/classic/schemas.ts", "packages/zod/src/v4/mini/schemas.ts"], "pr_body": "A TypeScript enum passed to `z.enum()` carries both directions of its mapping at runtime. The parse set drops the reverse half via `util.getEnumValues`, but `.options` was assigned straight from the entries object, so a three-member numeric enum listed six values — three of which the schema rejects.\n\n```ts\nenum Country {\n UK,\n Germany,\n France,\n}\n\nz.enum(Country).options; // [\"UK\", \"Germany\", \"France\", 0, 1, 2]\nz.enum(Country).safeParse(\"France\"); // { success: false }\n```\n\nThe declared type is `Array`, so the names were never admissible there either. The assignment now reuses the value set `$ZodEnum` already builds, which is what the parser checks against. Classic and mini both carried the line.\n\nA string enum is unchanged. A numeric enum now reports exactly what parse accepts.\n\nWeighed on all three axes, measured against the parent commit:\n\n| axis | result |\n| --- | --- |\n| bundle | −6 B raw on a classic and a mini enum fixture; gzipped within ±1 B either way |\n| memory | unchanged — `z.enum(['a','b','c'])` retains 1432 B on both revisions |\n| runtime | string enum construction unchanged; numeric enum construction ~6% faster, since the entries object is twice the size of the value set |\n\nRuntime is min-of-12 over 100k constructions, alternating revisions round by round across three rounds; the numeric-enum ranges do not overlap. The machine was loaded, so treat the absolute times as soft.", "pr_title": "Keep a numeric TS enum's reverse-mapping keys out of `.options`"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "69f2a7ff203e546e3a1350fb9152ace03ba0a6e6", "candidate_corpus": {"base_commit": "69f2a7ff203e546e3a1350fb9152ace03ba0a6e6", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "81ded9918fe39d51b232be72f23ba0d5fb6a837e", "negative_distractors": [], "related_tests": ["packages/zod/src/v4/classic/tests/validate.test.ts", "packages/zod/src/v4/core/tests/compile.test.ts"], "root_cause_files": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/parse.ts"], "root_cause_symbols": [], "supporting_files": ["wiki/compile.md"]}, "id": "8c75e4a2994b4e3fadcb2dac", "metadata": {"confidence": "weak", "created_at": "2026-08-31T20:28:09Z", "evidence": {"implementation_files": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/parse.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/validate.test.ts", "packages/zod/src/v4/core/tests/compile.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-31T21:47:08Z", "pr": 6538, "pr_url": "https://github.com/colinhacks/zod/pull/6538"}, "query": {"changed_file_summary": "2 implementation files and 2 existing test files changed within 5 total files.", "implementation_file_count": 2, "implementation_files": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/parse.ts"], "pr_body": "`z.validate` on a compiled schema re-ran the entire schema through the interpreter whenever the compiled validator rejected, just to reach the verdict the fast path had already produced.\n\nOften that second pass is dead work, because the compiled `INVALID` already means the runtime would reject — which is why a union can read a branch's `INVALID` as a rejection. Codegen now tracks a `definite` flag and `validate` skips the interpreted pass only while it survives. A call that passes a parse context still takes the interpreted path, since a context can change the verdict.\n\nTwo things clear the flag. Any hoisted **user callback** — a refine, transform, custom predicate, catch value or lazy getter — clears it, because that callback can throw and generated code can reject an earlier sibling before ever reaching it, so the rejection is no longer proof that the interpreter would have rejected rather than thrown. A **runtime island**, an **intersection**, and a **record key whose own compile is not definite** clear it directly. User code reaches generated code through a single `addUserConstant` helper that clears the flag, so a generator added later cannot quietly miss it.\n\nWhat keeps the fast path is the callback-free subset: type, range and format checks, enums, literals, unions, and object, array and tuple members. That is the shape a type guard is usually asked about.\n\nCompiled parsing semantics are untouched. The transform case is why this is a flag rather than a throw in generated code: a transform handing back a thenable has to keep answering `INVALID`, because the interpreter's own union falls through to the next branch there instead of propagating, and `compile-differential` pins that.\n\nInvalid input to a compiled callback-free schema, minimum of 7 samples across 3 inte\n...[truncated]", "pr_title": "perf: answer z.validate from the compiled fast path on invalid input"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "bf9902164b5396449540415c2221a24bc9fd0e22", "candidate_corpus": {"base_commit": "bf9902164b5396449540415c2221a24bc9fd0e22", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "abfb38977dc28dc9993e3fa6a2ecc2f52a8d0c4c", "negative_distractors": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/json-schema-processors.ts", "packages/zod/src/v4/core/memoizer.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/to-json-schema.ts", "packages/zod/src/v4/core/util.ts", "packages/zod/src/v4/core/visit.ts", "packages/zod/src/v4/mini/checks.ts"], "related_tests": ["packages/treeshake/bundle-size.test.ts", "packages/zod/src/v4/classic/tests/firstparty.test.ts", "packages/zod/src/v4/classic/tests/instanceof.test.ts"], "root_cause_files": ["packages/zod/src/v4/classic/checks.ts", "packages/zod/src/v4/classic/schemas.ts", "packages/zod/src/v4/core/api.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/json-schema-processors.ts", "packages/zod/src/v4/core/memoizer.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/to-json-schema.ts"], "root_cause_symbols": [], "supporting_files": ["packages/zod/src/v4/core/util.ts", "packages/zod/src/v4/core/visit.ts", "packages/zod/src/v4/mini/checks.ts", "packages/zod/src/v4/mini/schemas.ts", "packages/docs/content/api.mdx", "packages/zod/src/v4/classic/tests/properties.test.ts"]}, "id": "15fcd7ef7508cdd9fa5c3b44", "metadata": {"confidence": "weak", "created_at": "2026-08-31T19:13:09Z", "evidence": {"implementation_files": ["packages/zod/src/v4/classic/checks.ts", "packages/zod/src/v4/classic/schemas.ts", "packages/zod/src/v4/core/api.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/json-schema-processors.ts", "packages/zod/src/v4/core/memoizer.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/to-json-schema.ts", "packages/zod/src/v4/core/util.ts", "packages/zod/src/v4/core/visit.ts", "packages/zod/src/v4/mini/checks.ts", "packages/zod/src/v4/mini/schemas.ts"], "related_tests": ["packages/treeshake/bundle-size.test.ts", "packages/zod/src/v4/classic/tests/firstparty.test.ts", "packages/zod/src/v4/classic/tests/instanceof.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-31T21:06:27Z", "pr": 6536, "pr_url": "https://github.com/colinhacks/zod/pull/6536"}, "query": {"changed_file_summary": "12 implementation files and 3 existing test files changed within 17 total files.", "implementation_file_count": 12, "implementation_files": ["packages/zod/src/v4/classic/checks.ts", "packages/zod/src/v4/classic/schemas.ts", "packages/zod/src/v4/core/api.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/json-schema-processors.ts", "packages/zod/src/v4/core/memoizer.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/to-json-schema.ts"], "pr_body": "`z.properties(shape)` now constructs a real schema instead of an array of `z.property()` checks. It asserts the named properties in place and returns its input untouched — no new object, so prototypes, unlisted keys, and object identity survive. And because it's a schema, it finally infers. Follows up on #5912, which landed the check form; an array of checks can never narrow the type, and that was the reason to revisit it.\n\n```ts\nconst httpsUrl = z.instanceof(URL).properties({\n protocol: z.literal(\"https:\"),\n hostname: z.string().regex(z.regexes.domain),\n});\n\ntype HttpsUrl = z.infer;\n// => URL & { protocol: \"https:\"; hostname: string }\n```\n\nWhat's in here:\n\n- **`$ZodProperties`**, a core schema that is also a check, the way `$ZodCustom` is. As a schema it is the type gate — an object or a function, never a primitive — reports every failing key, and parses cyclic input — it returns the input identity, so the input registers as its own memo entry. It has cases in `z.compile()` (both roles), `z.toJSONSchema()` (`type: \"object\"` + `properties` + `required`, no `additionalProperties`; a symbol key is reported unrepresentable, as `z.object()` does), the memoizer, and `visit`.\n- **The 4.5 spread still works.** The schema yields itself from `Symbol.iterator`, so `z.instanceof(URL).check(...z.properties({ ... }))` keeps compiling and running; TypeScript infers the spread element type from the iterator. The spread now reports every failing property instead of stopping at the first, since one check iterates the whole shape. One caveat: consumers on `target: es5` lose the spread form (spreading a non-array iterable requires ES2015); the schema forms work everywhere.\n- **`z.instanceof()` returns a dedicated `ZodInstanceOf` class** with a `.properties()` method tha\n...[truncated]", "pr_title": "feat(v4): make z.properties() a schema, and give z.instanceof() a .properties() method"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "68a609ac9b9516e6fe84e3558f17ce16b1032bef", "candidate_corpus": {"base_commit": "68a609ac9b9516e6fe84e3558f17ce16b1032bef", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "07c43e2a08f67082bd35c158d528d571a36094e0", "negative_distractors": [], "related_tests": ["packages/zod/src/v4/classic/tests/string.test.ts", "packages/zod/src/v4/classic/tests/to-json-schema.test.ts"], "root_cause_files": ["packages/zod/src/v4/core/json-schema-processors.ts", "packages/zod/src/v4/core/schemas.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "bd28778ead2be13d7b598869", "metadata": {"confidence": "weak", "created_at": "2026-08-31T19:06:53Z", "evidence": {"implementation_files": ["packages/zod/src/v4/core/json-schema-processors.ts", "packages/zod/src/v4/core/schemas.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/string.test.ts", "packages/zod/src/v4/classic/tests/to-json-schema.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-31T20:01:18Z", "pr": 6534, "pr_url": "https://github.com/colinhacks/zod/pull/6534"}, "query": {"changed_file_summary": "2 implementation files and 2 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["packages/zod/src/v4/core/json-schema-processors.ts", "packages/zod/src/v4/core/schemas.ts"], "pr_body": "Fixes the finding from the #6528 review: `z.templateLiteral([\"id-\", z.base64url()]).safeParse` threw `RangeError: Maximum call stack size exceeded` on multi-megabyte input. The quantified block forms (`(?:[...]{4})*`) recurse per block in V8's regex engine, so ~8M chars overflows the stack. `z.base64()` and `z.base64url()` were already mitigated internally, but template literals compose member `def.pattern`s and test them on every parse.\n\nThe split, reworked per review: the public `z.regexes.base64` and `z.regexes.base64url` keep their strict shipped semantics and are untouched. The lax linear forms (`/^[0-9a-zA-Z+/]*={0,2}$/`, `/^[A-Za-z0-9_-]*$/`) live module-local in `schemas.ts` and become `def.pattern` for the two formats — parse validation is unchanged because `isValidBase64`/`isValidBase64URL` enforce the length rules. The JSON Schema emitter swaps the lax patterns back to the strict exports by reference, at both consumer sites: `stringProcessor`'s `pattern`/`allOf` and `recordProcessor`'s `patternProperties` (the review caught that `z.looseRecord(z.base64url(), …)` would otherwise emit the lax key — now pinned by a test). `toJSONSchema(z.base64url())` still emits the length-aware pattern from #6527; its snapshot and agreement tests pass unchanged, and `base64` gains the symmetric agreement test. `templateLiteralProcessor` is deliberately left lax: its emitted pattern then agrees with the (length-lax) composed parse.\n\nThis also fixes a second bug the overflow investigation surfaced: `regexes.base64`'s leading `^$|` alternation leaked through template-literal composition, so on `main` `z.templateLiteral([\"id-\", z.base64()])` accepts `\"AAAA\"` with the prefix dropped and rejects the valid `\"id-AAAA\"`. Both directions are now pinned by a test. Composed base64url segm\n...[truncated]", "pr_title": "Keep the runtime base64 regexes linear so composed parse paths cannot overflow"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "74f9a6d3f2818f24e6df5394b8b6e60acb176463", "candidate_corpus": {"base_commit": "74f9a6d3f2818f24e6df5394b8b6e60acb176463", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "2ec972ecc5a8af8135ed072d2d5b5363c27bb46f", "negative_distractors": [], "related_tests": ["packages/zod/src/v4/classic/tests/assignability.test.ts"], "root_cause_files": ["packages/zod/src/v4/core/util.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "5f579a7e295c70ea526d6c2a", "metadata": {"confidence": "weak", "created_at": "2026-08-31T18:21:29Z", "evidence": {"implementation_files": ["packages/zod/src/v4/core/util.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/assignability.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-31T19:07:26Z", "pr": 6533, "pr_url": "https://github.com/colinhacks/zod/pull/6533"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["packages/zod/src/v4/core/util.ts"], "pr_body": "Follow-up to #6528, from the request to find a smaller formulation than the mapped-key normalizer.\n\nThe enum-leaf machinery reduces to a single union. `{ [K in Extract]: K }[Extract] | Exclude` becomes `T | typeof toZodDummy`, where `toZodDummy` is a private, unexported `unique symbol`. Unioning either side with anything forces TypeScript to rebuild the union, and the rebuilt unions compare identical — `E | D` and `E.A | E.B | D` are the same type, while everything else the exactness check distinguishes stays distinguished. No index-signature lookup, no `Extract`/`Exclude` split. The recursive walk with its flat-rebuild guard stays: it is what keeps intersections, call signatures, classes with private members, and `readonly`/optional modifiers strict, and no leaf-level trick can reach a nested enum without it.\n\nVerified differentially: both implementations were run side by side over 35 probes — every fixed case (flat, nested, arrays, tuples, records, nullable, optional), every guarantee (`any`, `unknown`, brands, subsets, plain string literals vs a nominal enum, plain numeric literals vs a numeric enum, intersection-vs-flat, `readonly`, class instances with private members, enums nested in generics and function signatures) — with identical results on TypeScript 5.5, 6, and 7.0.2. The probe files live in the triage directory for #6524. The test suite gains one negative control: plain `1 | 2` does not satisfy a numeric enum target, which is the distinction the union rebuild had to preserve and the one place the two enum flavors differ (numeric enums are mutually *assignable* with their literals; identity still separates them).\n\nType-only change; zero runtime, memory, and bundle delta.", "pr_title": "Collapse toZod's enum leaf normalizer to a dummy union"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "a2a019a57e4444f61bf677ca79c1352823e2b7c8", "candidate_corpus": {"base_commit": "a2a019a57e4444f61bf677ca79c1352823e2b7c8", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "f83ab51129038a2f868ee11dda906ed78ae2e478", "negative_distractors": [], "related_tests": ["packages/zod/src/v4/classic/tests/continuability.test.ts", "packages/zod/src/v4/classic/tests/string.test.ts", "packages/zod/src/v4/classic/tests/to-json-schema.test.ts"], "root_cause_files": ["packages/zod/src/v4/core/regexes.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "03c677f1d077363c22040602", "metadata": {"confidence": "weak", "created_at": "2026-08-31T18:15:04Z", "evidence": {"implementation_files": ["packages/zod/src/v4/core/regexes.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/continuability.test.ts", "packages/zod/src/v4/classic/tests/string.test.ts", "packages/zod/src/v4/classic/tests/to-json-schema.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-31T18:44:33Z", "pr": 6532, "pr_url": "https://github.com/colinhacks/zod/pull/6532"}, "query": {"changed_file_summary": "1 implementation files and 3 existing test files changed within 4 total files.", "implementation_file_count": 1, "implementation_files": ["packages/zod/src/v4/core/regexes.ts"], "pr_body": "Fixes #6515.\n\n`z.emoji()` accepts strings built entirely from `\\p{Emoji_Component}` — `\"123\"`, `\"#\"`, `\"*\"`, a lone ZWJ, variation selector, or skin tone modifier — because that class is the set of pieces that combine with an emoji, not emoji themselves. This adds a leading lookahead requiring at least one anchor (an `Extended_Pictographic`, a regional indicator, or the enclosing keycap that makes `1️⃣` an emoji), and keeps the single-class body from #6347 so matching stays linear.\n\nThe pattern is emitted into `z.toJSONSchema()` output, so the two snapshots carrying it are updated, and `⃣` is spelled portably for non-ECMAScript consumers. Bundle cost is ~28 B gzipped in classic and zero in `zod/mini` unless `emoji()` is used.\n\nAuthored by @oleg6k; landing it from their branch since PR creation is currently restricted to collaborators. @NektarTheo had offered to pick this up — thanks to both.", "pr_title": "fix(v4): reject component-only strings from z.emoji()"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "eca96871536603076bdd00b8779b947144133aa4", "candidate_corpus": {"base_commit": "eca96871536603076bdd00b8779b947144133aa4", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "cafbee4772ef481611fef6f5fb9ed9a1b9597069", "negative_distractors": ["packages/zod/src/v4/core/util.ts", "packages/zod/src/v4/mini/schemas.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/cyclic-data.test.ts", "packages/zod/src/v4/classic/tests/object.test.ts"], "root_cause_files": ["packages/zod/src/v4/classic/schemas.ts", "packages/zod/src/v4/core/memoizer.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/util.ts", "packages/zod/src/v4/mini/schemas.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "27cdee9e2e1d2a5930f12bed", "metadata": {"confidence": "weak", "created_at": "2026-08-31T17:19:18Z", "evidence": {"implementation_files": ["packages/zod/src/v4/classic/schemas.ts", "packages/zod/src/v4/core/memoizer.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/util.ts", "packages/zod/src/v4/mini/schemas.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/cyclic-data.test.ts", "packages/zod/src/v4/classic/tests/object.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-01T01:54:11Z", "pr": 6530, "pr_url": "https://github.com/colinhacks/zod/pull/6530"}, "query": {"changed_file_summary": "5 implementation files and 2 existing test files changed within 7 total files.", "implementation_file_count": 5, "implementation_files": ["packages/zod/src/v4/classic/schemas.ts", "packages/zod/src/v4/core/memoizer.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/util.ts", "packages/zod/src/v4/mini/schemas.ts"], "pr_body": "Fixes #6526.\n\nA recursive schema built by a factory throws `RangeError: Maximum call stack size exceeded` on 4.5.x, after about eight seconds on the main thread. It parsed fine on 4.4.3. Published schemas hit it — `zod-geojson` builds its geometry schemas this way, so an empty feature collection crashes.\n\n```ts\nconst Node = (): any =>\n z.object({\n id: z.number(),\n get child() {\n return z.array(Node()); // a fresh instance on every read\n },\n });\n\nz.object({ root: Node() }).parse({ root: { id: 1, child: [] } }); // RangeError\n```\n\nThe cycle walk added in #6387 decides whether a parse can re-enter the same schema, so the memoizer can detach when no cycle is possible. Instance identity is the only thing that terminates that walk: it marks what it enters and stops when it meets a mark. A factory returns a new instance per call, so resolving one getter mints a whole new subtree, the walk never revisits a node, and it constructs schemas until the stack runs out. Descent at parse time was always data-directed and therefore finite, which is why 4.4.3 was unaffected.\n\n## The rule\n\nThe walk no longer resolves anything that runs user code, and reports a cycle for every edge it therefore cannot follow — a shape getter, or a `z.lazy` nobody has resolved. That terminates by construction and needs no depth limit. It errs in one direction only: it can report a cycle that does not exist, never the reverse. The same rule already governs `compile.ts`, which treats \"can't tell\" as recursive.\n\nLeft alone, that would pin the memoizer to every non-cyclic getter and `z.lazy` — about 2.3x on a small object parse. So the conservative answer is neither cached nor latched. The first parse resolves the getters along its path and `z.lazy` stores its inner type on the def, and one rech\n...[truncated]", "pr_title": "fix(v4): parse recursive schemas built by a factory"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "319f47f44f40755773a9aa83b6fdaaad1ff01d77", "candidate_corpus": {"base_commit": "319f47f44f40755773a9aa83b6fdaaad1ff01d77", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "a2a019a57e4444f61bf677ca79c1352823e2b7c8", "negative_distractors": [], "related_tests": ["packages/zod/src/v4/classic/tests/assignability.test.ts"], "root_cause_files": ["packages/zod/src/v4/core/util.ts"], "root_cause_symbols": [], "supporting_files": ["packages/docs/content/basics.mdx"]}, "id": "f467f3f443a72bbf45ac2321", "metadata": {"confidence": "weak", "created_at": "2026-08-31T17:04:23Z", "evidence": {"implementation_files": ["packages/zod/src/v4/core/util.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/assignability.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-31T17:26:13Z", "pr": 6528, "pr_url": "https://github.com/colinhacks/zod/pull/6528"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["packages/zod/src/v4/core/util.ts"], "pr_body": "Fixes #6524.\n\n`z.toZod()` rejected `z.enum(SomeEnum)` against a property typed `SomeEnum`, with the unhelpful diagnostic `expected: SomeEnum, received: SomeEnum`. TypeScript doesn't consider an enum reference identical to the union of exactly its own members, and the union is the only output type `z.enum` can infer from `typeof SomeEnum` — so no schema could ever satisfy an enum-typed property. The equivalent member-union target worked, which is the asymmetry the issue reports. This was also flagged during review on #5913 and hit by a user in the first canary.\n\nThe fix keeps exact identity as the fast path and adds a fallback: rebuild the `string | number` part of each side through a mapped key type (`{ [K in T]: K }[T]`), which collapses the enum-reference/member-union difference and nothing else, then re-check identity. The walk recurses only through types identical to their own homomorphic rebuild, so every guarantee the exactness decision in #5913 protects is preserved — `any` (explicit guards), `readonly` and optional modifiers, intersection-vs-flat, brands, member subsets, and plain `\"A\" | \"B\"` literals against a nominal enum all still fail. Enum targets now work at any depth, including arrays, tuples, records, nullables, and recursive types.\n\nType-only change: zero runtime, memory, and bundle delta. The fallback only instantiates where the fast path already failed, so typecheck cost lands on error paths and newly-valid enum paths; the repo's own typecheck time is unchanged.", "pr_title": "Accept enum-typed targets in z.toZod"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "93f3ab321211f52f1963b63d5d3503c645c38371", "candidate_corpus": {"base_commit": "93f3ab321211f52f1963b63d5d3503c645c38371", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "68a609ac9b9516e6fe84e3558f17ce16b1032bef", "negative_distractors": [], "related_tests": ["packages/zod/src/v4/classic/tests/instanceof.test.ts", "packages/zod/src/v4/mini/tests/checks.test.ts"], "root_cause_files": ["packages/zod/src/v4/core/api.ts", "packages/zod/src/v4/core/util.ts"], "root_cause_symbols": [], "supporting_files": ["packages/docs/content/api.mdx", "packages/docs/content/blog/zod-4-5.mdx"]}, "id": "afb0614773a4e72fdd471e26", "metadata": {"confidence": "weak", "created_at": "2026-08-29T23:51:59Z", "evidence": {"implementation_files": ["packages/zod/src/v4/core/api.ts", "packages/zod/src/v4/core/util.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/instanceof.test.ts", "packages/zod/src/v4/mini/tests/checks.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-31T18:59:10Z", "pr": 6520, "pr_url": "https://github.com/colinhacks/zod/pull/6520"}, "query": {"changed_file_summary": "2 implementation files and 2 existing test files changed within 6 total files.", "implementation_file_count": 2, "implementation_files": ["packages/zod/src/v4/core/api.ts", "packages/zod/src/v4/core/util.ts"], "pr_body": "`z.property(\"protocol\", z.literal(\"https:\"))` on a `URL` did not compile: the check was typed over `{ protocol: \"https:\" }`, and a `string` property is not assignable to that. Every literal, enum or boolean property check needed an `as string` / `as boolean` cast, and the docs have been showing one since #4863.\n\nThe check is now typed over the widened input of its schema, so `\"https:\"` becomes `string` and `false` becomes `boolean`:\n\n```ts\nz.instanceof(Request).check(\n ...z.properties({\n method: z.enum([\"POST\", \"PUT\"]),\n bodyUsed: z.literal(false),\n })\n);\n```\n\nA genuine mismatch (`z.property(\"length\", z.string())` on a string) and an unknown key still fail to compile; both are pinned in the test. Type-only change, so no runtime, memory or bundle impact. The casts are dropped from the docs, the 4.5 blog post and the tests.\n\nRefs #5912", "pr_title": "Widen literal inputs in property check types"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "43b9bfc5a59167b42c897eb9c74129fc8b4c31e4", "candidate_corpus": {"base_commit": "43b9bfc5a59167b42c897eb9c74129fc8b4c31e4", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "cd4f9a679238a5470620f74c2cc568e8865b3f01", "negative_distractors": [], "related_tests": ["packages/treeshake/bundle-size.test.ts", "packages/zod/src/v4/classic/tests/standard-schema.test.ts"], "root_cause_files": ["packages/zod/src/v4/core/schemas.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "30bdae84f5412e13fd6725ed", "metadata": {"confidence": "weak", "created_at": "2026-08-29T20:26:17Z", "evidence": {"implementation_files": ["packages/zod/src/v4/core/schemas.ts"], "related_tests": ["packages/treeshake/bundle-size.test.ts", "packages/zod/src/v4/classic/tests/standard-schema.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-29T20:32:03Z", "pr": 6509, "pr_url": "https://github.com/colinhacks/zod/pull/6509"}, "query": {"changed_file_summary": "1 implementation files and 2 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["packages/zod/src/v4/core/schemas.ts"], "pr_body": "A Standard Schema result only reports issues, but a failing `~standard.validate` built a full `ZodError` and then read `.issues` off it. It now parses with a plain issue holder as the error class, so the finalized issues are the whole cost.\n\nFailing `~standard.validate` goes from 1051 to 418 ns on a two-issue object (Node 26.7, Apple Silicon, best of 4 interleaved rounds against `main`); valid input and every `safeParse`/`parse` path are unchanged. Retained bytes per failing result are unchanged. Bundles grow 21 B gzipped on the mini fixtures, and the ceilings are raised by that in the same commit.", "pr_title": "perf(v4): report Standard Schema issues without constructing a ZodError"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "e8e206fa33ac5fe7ce20a2beb12d57b1cb3df653", "candidate_corpus": {"base_commit": "e8e206fa33ac5fe7ce20a2beb12d57b1cb3df653", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "c46eeff050f2a6a2ba8db1d14c2c8247bd7623f2", "negative_distractors": ["packages/zod/src/v4/core/errors.ts", "packages/zod/src/v4/core/to-json-schema.ts", "scripts/compile-fuzz.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/recursive-types.test.ts"], "root_cause_files": ["packages/bench/object-setup.ts", "packages/docs/components/scroller.tsx", "packages/zod/src/v3/helpers/errorUtil.ts", "packages/zod/src/v4/core/errors.ts", "packages/zod/src/v4/core/to-json-schema.ts", "scripts/compile-fuzz.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "496e93cbb5a9b40c45c14929", "metadata": {"confidence": "weak", "created_at": "2026-08-29T18:33:34Z", "evidence": {"implementation_files": ["packages/bench/object-setup.ts", "packages/docs/components/scroller.tsx", "packages/zod/src/v3/helpers/errorUtil.ts", "packages/zod/src/v4/core/errors.ts", "packages/zod/src/v4/core/to-json-schema.ts", "scripts/compile-fuzz.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/recursive-types.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-29T19:52:46Z", "pr": 6504, "pr_url": "https://github.com/colinhacks/zod/pull/6504"}, "query": {"changed_file_summary": "6 implementation files and 1 existing test files changed within 7 total files.", "implementation_file_count": 6, "implementation_files": ["packages/bench/object-setup.ts", "packages/docs/components/scroller.tsx", "packages/zod/src/v3/helpers/errorUtil.ts", "packages/zod/src/v4/core/errors.ts", "packages/zod/src/v4/core/to-json-schema.ts", "scripts/compile-fuzz.ts"], "pr_body": "Picks up the patch from #6503.\n\nThere were six suppressions in the repo that either said nothing (`// biome-ignore lint:`) or still carried biome's `` placeholder. A bare `biome-ignore lint:` silences every rule at that line, so the next real violation to appear there goes unreported. Each one now names the rule it suppresses and why.\n\nTwo of them turned out to be unnecessary. `DATA` in `packages/bench/object-setup.ts` is only ever imported, never reassigned, so it's `const` now — and the `noInnerDeclarations` ignore stacked above it never fired at all, since the declaration is top-level. The compile fuzzer also had a `catch (e)` binding it doesn't use, which was tripping `noUnusedVariables` with no suppression at all.\n\nI confirmed each rule name against biome's actual output rather than taking them on faith, and verified the two rationales that make a claim: `errorUtil.toString` has 31 call sites in v3, and dropping `export` from `RecursiveA` makes `tsc` fail with TS6196 under `noUnusedLocals`, which is what that export is there for.\n\nNo behavior changes. The two `core/` files are comment-only, so all three axes are untouched.\n\n\n\n\"Pullfrog\"  | [View workflow run](https://github.com/colinhacks/zod/actions/runs/33268327091/job/99142234577) | via [Pullfrog](https://pullfrog.com) | Using `Claude Opus` | [𝕏](https://x.com/pullfrogai)", "pr_title": "chore: narrow blanket biome-ignore comments"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "e6b6ab347675cd2bd54b1bdbed16f98c59be82a9", "candidate_corpus": {"base_commit": "e6b6ab347675cd2bd54b1bdbed16f98c59be82a9", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "eab51ff3592b2d11d863f4ee4d5452f31a3de1b6", "negative_distractors": [], "related_tests": ["packages/zod/src/v4/classic/tests/to-json-schema.test.ts"], "root_cause_files": ["packages/zod/src/v4/core/json-schema-processors.ts", "packages/zod/src/v4/core/to-json-schema.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "4dac5cbdbd9f22db913cb45a", "metadata": {"confidence": "weak", "created_at": "2026-08-29T15:15:46Z", "evidence": {"implementation_files": ["packages/zod/src/v4/core/json-schema-processors.ts", "packages/zod/src/v4/core/to-json-schema.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/to-json-schema.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-29T17:15:17Z", "pr": 6497, "pr_url": "https://github.com/colinhacks/zod/pull/6497"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 2, "implementation_files": ["packages/zod/src/v4/core/json-schema-processors.ts", "packages/zod/src/v4/core/to-json-schema.ts"], "pr_body": "JSON object keys are always strings, so `propertyNames: { type: \"number\" }` matches no key. A record with a numeric key emitted a schema that accepts only `{}`, while the Zod schema accepts `{ \"1\": 2 }`.\n\nA numeric-literal key was worse. `z.record(z.literal([1, 2]), z.number())` emitted `required: [1, 2]`, and `required` is an array of strings in every draft — Ajv refuses to compile it. That one affected all four targets, including `openapi-3.0`.\n\nBoth are string positions now. Discrete numeric key values are stringified, and a bare numeric key type is re-expressed as a string carrying the same regex the record parser gates on before it retries a key as a number, so the output for a `z.number()` key is exact rather than approximate. Numeric-only keywords like `minimum` are dropped, since they cannot constrain a string.\n\n```ts\nz.toJSONSchema(z.record(z.number(), z.boolean())).propertyNames;\n// before: { type: \"number\" }\n// after: { type: \"string\", pattern: \"^-?\\\\d+(?:\\\\.\\\\d+)?$\" }\n```\n\nThe rewrite runs from `finalize` rather than at emit time, because a key behind `z.lazy`, `.pipe()` or `.readonly()` has no `type` of its own until the flatten merges the inner one, and a union key keeps its branches under `anyOf`. It recurses into those branches, resolves an extracted key through its definition — inlining the string form a key position needs, while a key with nothing to re-express keeps its `$ref` — and updates every carrier the flatten copied `propertyNames` onto, so a wrapped record does not keep the old shape. A recursive key terminates on revisit instead of looping.\n\nVerified by emitting 33 record shapes on `main` and on this branch, compiling each with Ajv and comparing against the schema's own `safeParse`: no case is worse here, 24 are better, and the six schemas `\n...[truncated]", "pr_title": "fix(v4): emit record numeric keys as strings in toJSONSchema"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "773a48676ede1a2144d4f2e60892e6c0cd6625a7", "candidate_corpus": {"base_commit": "773a48676ede1a2144d4f2e60892e6c0cd6625a7", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "fb3af01f76d9b249fc3a251eab79e12764b1c7ad", "negative_distractors": ["packages/zod/src/v4/core/memoizer.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/mini/external.ts"], "related_tests": ["packages/treeshake/bundle-size.test.ts", "packages/zod/src/v4/classic/tests/cyclic-data.test.ts"], "root_cause_files": ["packages/zod/src/v4/classic/external.ts", "packages/zod/src/v4/classic/schemas.ts", "packages/zod/src/v4/core/core.ts", "packages/zod/src/v4/core/memoizer.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/mini/external.ts"], "root_cause_symbols": [], "supporting_files": ["packages/docs/content/api.mdx", "packages/zod/src/v4/mini/tests/cyclic-data.test.ts"]}, "id": "70107988cae0371bd6fd7963", "metadata": {"confidence": "weak", "created_at": "2026-08-28T16:01:34Z", "evidence": {"implementation_files": ["packages/zod/src/v4/classic/external.ts", "packages/zod/src/v4/classic/schemas.ts", "packages/zod/src/v4/core/core.ts", "packages/zod/src/v4/core/memoizer.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/mini/external.ts"], "related_tests": ["packages/treeshake/bundle-size.test.ts", "packages/zod/src/v4/classic/tests/cyclic-data.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-28T17:13:11Z", "pr": 6482, "pr_url": "https://github.com/colinhacks/zod/pull/6482"}, "query": {"changed_file_summary": "6 implementation files and 2 existing test files changed within 10 total files.", "implementation_file_count": 6, "implementation_files": ["packages/zod/src/v4/classic/external.ts", "packages/zod/src/v4/classic/schemas.ts", "packages/zod/src/v4/core/core.ts", "packages/zod/src/v4/core/memoizer.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/mini/external.ts"], "pr_body": "Follow-up to #6387. The cycle memoizer was wired into classic only — each container called `attachMemoizer` before its init — and `zod/mini` had no way to get it. It is now a config field, read when a schema is constructed:\n\n```ts\nimport * as z from \"zod/mini\";\n\nz.config({ memoizer: z.memoizer() });\n```\n\nRegular `zod` installs it by default on the first container construction, through the same hook as the default locale and for the same `sideEffects: false` reason.\n\nOne global memoizer replaces the per-instance objects. The handoff slot and the open-entry stack are module state — both are set and consumed in the synchronous part of one parse, so they nest across schemas — and the per-instance part (the recursive flag, the bucket cache) lives in the wrapper's closure. The `_zod.memoizer` field is gone. The wrap now runs after core's own `run = parse` deferred, so it patches `run` when core had copied the base parse into it.\n\nThe back-edge guard on a transform also rides the seam: the memoizer's `guard` wraps `$ZodTransform`'s parse when one is configured, so an opted-in mini rejects a cycle that closes through a transform exactly as classic does, and a mini bundle without the opt-in carries none of it.\n\nThe \"cyclical data will cause an infinite loop\" callout in the docs has been stale since #6387; it is replaced with a Zod / Zod Mini tabbed example that shows the opt-in inline.\n\nSince the config is global, a process that loads both `zod` and `zod/mini` gives mini schemas the memoizer too once classic has built a container — same as the default locale.\n\nBundle (esbuild `--minify`, gzip -9):\n\n| fixture | main | this PR |\n|---|---|---|\n| `zod-object` (classic) | 24223 | 24244 (+21) |\n| `zod-mini-object` | 4497 | 4491 (−6) |\n| `zod-mini-object` + `z.memoizer()` | — | 5099 (+\n...[truncated]", "pr_title": "feat(v4): expose the memoizer through z.config() so zod/mini can opt in"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "37b015017b17420e81e76555066bdfa39c24cdc5", "candidate_corpus": {"base_commit": "37b015017b17420e81e76555066bdfa39c24cdc5", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "68fb3f1381f7cb1ad3bd786544383f8290422d3b", "negative_distractors": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/mini/external.ts", "scripts/compile-fuzz.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/object.test.ts", "packages/zod/src/v4/core/tests/compile-differential.test.ts", "packages/zod/src/v4/core/tests/compile.test.ts"], "root_cause_files": ["packages/bench/compile-matrix.ts", "packages/zod/src/compile.ts", "packages/zod/src/v4/classic/external.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/mini/external.ts", "scripts/compile-fuzz.ts"], "root_cause_symbols": [], "supporting_files": ["packages/docs/content/compile.mdx", "packages/zod/README.md", "wiki/compile-plan.md", "wiki/compile.md"]}, "id": "ef2b14a82a68c9831bf18d81", "metadata": {"confidence": "weak", "created_at": "2026-08-28T04:38:48Z", "evidence": {"implementation_files": ["packages/bench/compile-matrix.ts", "packages/zod/src/compile.ts", "packages/zod/src/v4/classic/external.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/mini/external.ts", "scripts/compile-fuzz.ts"], "related_tests": ["packages/zod/src/v4/classic/tests/object.test.ts", "packages/zod/src/v4/core/tests/compile-differential.test.ts", "packages/zod/src/v4/core/tests/compile.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-28T05:26:05Z", "pr": 6479, "pr_url": "https://github.com/colinhacks/zod/pull/6479"}, "query": {"changed_file_summary": "6 implementation files and 3 existing test files changed within 13 total files.", "implementation_file_count": 6, "implementation_files": ["packages/bench/compile-matrix.ts", "packages/zod/src/compile.ts", "packages/zod/src/v4/classic/external.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/mini/external.ts", "scripts/compile-fuzz.ts"], "pr_body": "Compiling a schema throws today when the fast path can't be built — a reference cycle, an async refinement, an unsupported node at the root. Global mode never has: `import \"zod/compile\"` quietly leaves those schemas on the standard parser. Same compiler, two entry points, opposite failure behavior, and the explicit one can take an app down over what is only a lost optimization.\n\nThe default now matches global mode. A refused schema comes back unchanged, still on the standard parser:\n\n```ts\nconst Schema = z.string().refine(async (val) => isAvailable(val));\n\nz.compile(Schema); // returns Schema itself, uncompiled\nz.compile(Schema, { strict: true }); // throws ZodCompileAsyncError\n```\n\nError classes and messages are untouched under `strict`. Three callers pass it: the bench matrix and the fuzzer because they classify refusals, and the global shim because a non-strict compile would hand it back the instance whose `run` is the shim and reinstall it on itself.\n\nNested behavior is unchanged — an unsupported child inside a container still becomes a runtime island. I left async as a whole-schema fallback rather than islanding it; proving `$ZodAsyncError` surfaces identically through generated code needs a differential matrix I don't think the payoff justifies yet.\n\nOn the three axes: the generated code is byte-identical (eight fixtures hashed on both revisions), so the parse path doesn't move and no schema instance gains a property; bundle cost is zero for anything that doesn't call `z.compile`, and 46 B raw / 22–26 B gzipped for anything that does.", "pr_title": "feat(v4): make z.compile() fall back instead of throwing"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "37b015017b17420e81e76555066bdfa39c24cdc5", "candidate_corpus": {"base_commit": "37b015017b17420e81e76555066bdfa39c24cdc5", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "773a48676ede1a2144d4f2e60892e6c0cd6625a7", "negative_distractors": ["packages/zod/src/v4/core/errors.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/util.ts", "packages/zod/src/v4/mini/schemas.ts"], "related_tests": ["packages/treeshake/bundle-size.test.ts", "packages/zod/src/v4/classic/tests/instance-footprint.test.ts"], "root_cause_files": ["packages/zod/src/v4/classic/errors.ts", "packages/zod/src/v4/classic/schemas.ts", "packages/zod/src/v4/core/core.ts", "packages/zod/src/v4/core/errors.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/util.ts", "packages/zod/src/v4/mini/schemas.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "4d0aefa2479b3aa90a6019a6", "metadata": {"confidence": "weak", "created_at": "2026-08-28T00:31:45Z", "evidence": {"implementation_files": ["packages/zod/src/v4/classic/errors.ts", "packages/zod/src/v4/classic/schemas.ts", "packages/zod/src/v4/core/core.ts", "packages/zod/src/v4/core/errors.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/util.ts", "packages/zod/src/v4/mini/schemas.ts"], "related_tests": ["packages/treeshake/bundle-size.test.ts", "packages/zod/src/v4/classic/tests/instance-footprint.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-28T06:18:39Z", "pr": 6478, "pr_url": "https://github.com/colinhacks/zod/pull/6478"}, "query": {"changed_file_summary": "7 implementation files and 2 existing test files changed within 9 total files.", "implementation_file_count": 7, "implementation_files": ["packages/zod/src/v4/classic/errors.ts", "packages/zod/src/v4/classic/schemas.ts", "packages/zod/src/v4/core/core.ts", "packages/zod/src/v4/core/errors.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/util.ts", "packages/zod/src/v4/mini/schemas.ts"], "pr_body": "A trait's members were installed from inside its per-instance initializer, by one of two installers, each handed a sentinel key naming a member of the group it was about to install:\n\n```ts\n_installLazyMethods(inst, \"check\", _zodTypeMethods);\n_installLazyProps(inst, \"parse\", _zodTypeParseProps);\n```\n\nThe work is per prototype, but the initializer runs per instance, so every construction re-asked a question whose answer could not change. The tables floated at module scope, reachable only through those two calls. And the split between the two was not a real distinction.\n\n`$constructor` takes the members instead, written the way they read on the instance:\n\n```ts\nexport const ZodString: core.$constructor = core.$constructor(\n \"ZodString\",\n (inst, def) => {\n core.$ZodString.init(inst, def);\n _ZodString.init(inst, def);\n },\n {\n email(params) {\n return this.check(core._email(ZodEmail, params));\n },\n // ...\n }\n);\n```\n\nIt installs them once on every prototype that composes the trait. Composition still flattens through `init`, so a trait's members reach every prototype below it without being re-listed anywhere — there is no parent list to keep in sync. The sentinels are gone; idempotence is a set of the prototypes already done.\n\nTwo forms remain and both are ordinary JavaScript, meaning what they already mean. A **method** materializes bound to the instance on first read and caches as an own property — binding is what keeps `const opt = schema.optional; opt()` working, which `detached-methods.test.ts` pins across about thirty members. A **getter** installs as written and stays live, which `description` needs to read through to the registry on every access.\n\n`ProtoOf` is a partial view of the trait's own interface with `this` typed\n...[truncated]", "pr_title": "refactor(v4): declare a trait's members on $constructor"}, "query_provenance": "pr_summary", "repo": "colinhacks/zod", "task_type": "code2test", "version": 2} +{"base_commit": "b0d28c42987c0c8a4e3c99cdbbbb57450e06dfda", "candidate_corpus": {"base_commit": "b0d28c42987c0c8a4e3c99cdbbbb57450e06dfda", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "1d029dcedd4b8cd7eaed718efe5dfa2f5bab9b30", "negative_distractors": [], "related_tests": ["src/router/common.case.test.ts", "src/utils/url.test.ts"], "root_cause_files": ["src/router/reg-exp-router/trie.ts", "src/utils/url.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "a80a0a56cb1f7e56d7d444a1", "metadata": {"confidence": "weak", "created_at": "2026-10-12T02:04:52Z", "evidence": {"implementation_files": ["src/router/reg-exp-router/trie.ts", "src/utils/url.ts"], "related_tests": ["src/router/common.case.test.ts", "src/utils/url.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-16T09:56:35Z", "pr": 5552, "pr_url": "https://github.com/honojs/hono/pull/5552"}, "query": {"changed_file_summary": "2 implementation files and 2 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["src/router/reg-exp-router/trie.ts", "src/utils/url.ts"], "pr_body": "Route patterns such as `/x/:prefix{a{2}/b}/x` should match `/x/aa/b/x`, capturing `aa/b` as `prefix`.\n\nCurrently, pattern masking stops at the quantifier’s closing `}`, leaving the following `/` exposed to path splitting.\n\nThis is a fairly rare edge case, so I hesitated over whether it was worth adding code to support it. However, the routing syntax allows this pattern, so I’m opening this PR.\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code", "pr_title": "fix(router): handle slashes after regex quantifiers"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "cc92a59f60caf7fe4f61cd01d0d6afb66426c6ae", "candidate_corpus": {"base_commit": "cc92a59f60caf7fe4f61cd01d0d6afb66426c6ae", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "5c292393f21e1693b54a6081491e4e83215d02ea", "negative_distractors": [], "related_tests": ["runtime-tests/bun/index.test.tsx", "src/request.test.ts"], "root_cause_files": ["src/request.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "58488b8cce82b9cd8e340857", "metadata": {"confidence": "weak", "created_at": "2026-10-07T06:38:55Z", "evidence": {"implementation_files": ["src/request.ts"], "related_tests": ["runtime-tests/bun/index.test.tsx", "src/request.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-09T03:53:07Z", "pr": 5536, "pr_url": "https://github.com/honojs/hono/pull/5536"}, "query": {"changed_file_summary": "1 implementation files and 2 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/request.ts"], "pr_body": "### Validate Content-Length: c169ae46\n\nRe-encoding cached text can change the body’s byte length, leaving the original Content-Length stale and causing forwarded requests to fail. This fix prevents stale length headers from being reused after `arrayBuffer()` reads or repeated cloning.\n\n### Return independent JSON objects: ddb5c128\n\nSharing the parsed object would carry mutations into subsequent calls, so this change preserves the previous behavior of returning independent objects. Since `json()` is typically called only once per request, parsing the cached text on each call is expected to have little performance impact.\n\n### Read Content-Type before consuming the body: c97181a6\n\nOn Bun, the following command fails with a `500` response before this commit. Reading Content-Type before consuming the body preserves the matching multipart boundary and makes it return `200 b`.\n\n```sh\nbun -e \"const { Hono } = await import('./src/index'); const app = new Hono(); app.onError((e, c) => c.text(e.message, 500)); app.post('/', async (c) => c.text(String((await c.req.formData()).get('a')))); const fd = new FormData(); fd.append('a', 'b'); const res = await app.request('/', { method: 'POST', body: fd }); console.log(res.status, await res.text())\"\n```\n\n### Return cached representations first: f7d4c67c\n\nReading an externally cached body representation could trigger an unhandled rejection after the raw body had already been consumed.", "pr_title": "preserve body cache behavior across runtimes"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "371b2877e3a5869e13f808fbc4778603978b7127", "candidate_corpus": {"base_commit": "371b2877e3a5869e13f808fbc4778603978b7127", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "2772c28f7a8304edec67a9eface937841cee1f74", "negative_distractors": [], "related_tests": ["src/context.test.ts"], "root_cause_files": ["src/context.ts"], "root_cause_symbols": [], "supporting_files": ["docs/MIGRATION.md"]}, "id": "2700f42ede145f6e77db12b3", "metadata": {"confidence": "weak", "created_at": "2026-10-06T12:24:36Z", "evidence": {"implementation_files": ["src/context.ts"], "related_tests": ["src/context.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-06T12:26:57Z", "pr": 5534, "pr_url": "https://github.com/honojs/hono/pull/5534"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/context.ts"], "pr_body": "Fixes #2343\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code", "pr_title": "feat(context)!: throw on a value that is not JSON serializable in `c.json()`"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "52944f0642fa0f210711159c549fcd2a96d306f3", "candidate_corpus": {"base_commit": "52944f0642fa0f210711159c549fcd2a96d306f3", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "371b2877e3a5869e13f808fbc4778603978b7127", "negative_distractors": [], "related_tests": ["src/request.test.ts"], "root_cause_files": ["src/request.ts"], "root_cause_symbols": [], "supporting_files": ["docs/MIGRATION.md"]}, "id": "d3aeaad9960356e0b0ee15fa", "metadata": {"confidence": "weak", "created_at": "2026-10-06T12:14:38Z", "evidence": {"implementation_files": ["src/request.ts"], "related_tests": ["src/request.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-06T12:16:52Z", "pr": 5533, "pr_url": "https://github.com/honojs/hono/pull/5533"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/request.ts"], "pr_body": "Resolves https://github.com/orgs/honojs/discussions/4979\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code", "pr_title": "feat(request)!: `json()` returns unknown"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "2fa7732e1b1b4b81c43a643be2cf22f0947a8d9a", "candidate_corpus": {"base_commit": "2fa7732e1b1b4b81c43a643be2cf22f0947a8d9a", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "52944f0642fa0f210711159c549fcd2a96d306f3", "negative_distractors": [], "related_tests": ["src/hono.test.ts", "src/request.test.ts"], "root_cause_files": ["src/request.ts", "src/validator/validator.ts"], "root_cause_symbols": [], "supporting_files": ["docs/MIGRATION.md"]}, "id": "64dce6a56efcc3a10d441c03", "metadata": {"confidence": "weak", "created_at": "2026-10-06T12:07:15Z", "evidence": {"implementation_files": ["src/request.ts", "src/validator/validator.ts"], "related_tests": ["src/hono.test.ts", "src/request.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-06T12:09:40Z", "pr": 5532, "pr_url": "https://github.com/honojs/hono/pull/5532"}, "query": {"changed_file_summary": "2 implementation files and 2 existing test files changed within 5 total files.", "implementation_file_count": 2, "implementation_files": ["src/request.ts", "src/validator/validator.ts"], "pr_body": "Fixes https://github.com/honojs/hono/issues/3426\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code", "pr_title": "feat(request)!: `query()` and `queries()` may return `undefined`"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "08a023cbfde55b434fb0fb30fae35d42e4bf20aa", "candidate_corpus": {"base_commit": "08a023cbfde55b434fb0fb30fae35d42e4bf20aa", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "588ec13fa68ea44fed1b5e1b503341db2bf09d70", "negative_distractors": [], "related_tests": ["src/middleware/serve-static/index.test.ts"], "root_cause_files": ["src/middleware/serve-static/index.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "a9679a27c78fa49e1d37b553", "metadata": {"confidence": "weak", "created_at": "2026-10-04T13:16:03Z", "evidence": {"implementation_files": ["src/middleware/serve-static/index.ts"], "related_tests": ["src/middleware/serve-static/index.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-13T08:18:10Z", "pr": 5514, "pr_url": "https://github.com/honojs/hono/pull/5514"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["src/middleware/serve-static/index.ts"], "pr_body": "#5223\n\nCall `next()` for requests other than GET and HEAD.\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code", "pr_title": "fix(serve-static): only serve GET and HEAD requests"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "b819e533ad9ec1d3d1ab1cf9316a78a2ccde9303", "candidate_corpus": {"base_commit": "b819e533ad9ec1d3d1ab1cf9316a78a2ccde9303", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "9e4a7fb57c8c1dbca9d345c5335f527e05fede5b", "negative_distractors": [], "related_tests": ["src/hono.test.ts"], "root_cause_files": ["src/hono-base.ts"], "root_cause_symbols": [], "supporting_files": ["docs/MIGRATION.md"]}, "id": "ff2929bc1445b2eb853bfccf", "metadata": {"confidence": "weak", "created_at": "2026-10-04T04:03:29Z", "evidence": {"implementation_files": ["src/hono-base.ts"], "related_tests": ["src/hono.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-04T04:06:30Z", "pr": 5511, "pr_url": "https://github.com/honojs/hono/pull/5511"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/hono-base.ts"], "pr_body": "### The author should do the following, if applicable\n\n- [ ] Add tests\n- [ ] Run tests\n- [ ] `pnpm run check:fix` to format and lint the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code", "pr_title": "chore!: remove deprecated `app.mount()`"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "6969cd9c869e3743444b96e861cc7c31d02e0263", "candidate_corpus": {"base_commit": "6969cd9c869e3743444b96e861cc7c31d02e0263", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "0d71f60ddffff089e6fa3c658730e3a0a7e1e5e1", "negative_distractors": [], "related_tests": ["src/utils/buffer.test.ts"], "root_cause_files": ["src/middleware/basic-auth/index.ts", "src/middleware/bearer-auth/index.ts", "src/utils/buffer.ts"], "root_cause_symbols": [], "supporting_files": ["docs/MIGRATION.md"]}, "id": "5ccc15d66507fd8e1a9748b7", "metadata": {"confidence": "weak", "created_at": "2026-10-02T09:45:04Z", "evidence": {"implementation_files": ["src/middleware/basic-auth/index.ts", "src/middleware/bearer-auth/index.ts", "src/utils/buffer.ts"], "related_tests": ["src/utils/buffer.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-02T09:49:04Z", "pr": 5502, "pr_url": "https://github.com/honojs/hono/pull/5502"}, "query": {"changed_file_summary": "3 implementation files and 1 existing test files changed within 5 total files.", "implementation_file_count": 3, "implementation_files": ["src/middleware/basic-auth/index.ts", "src/middleware/bearer-auth/index.ts", "src/utils/buffer.ts"], "pr_body": "### The author should do the following, if applicable\n\n- [ ] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code", "pr_title": "chore!(utils): make timingSafeEqual string-only"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "59dc47d7be4ea39ce3a5423995200a97075e6436", "candidate_corpus": {"base_commit": "59dc47d7be4ea39ce3a5423995200a97075e6436", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "6969cd9c869e3743444b96e861cc7c31d02e0263", "negative_distractors": [], "related_tests": ["src/helper/ssg/ssg.test.tsx"], "root_cause_files": ["src/helper/ssg/ssg.ts"], "root_cause_symbols": [], "supporting_files": ["docs/MIGRATION.md"]}, "id": "f293bd9f4c95d8681abf1eef", "metadata": {"confidence": "weak", "created_at": "2026-10-02T09:34:59Z", "evidence": {"implementation_files": ["src/helper/ssg/ssg.ts"], "related_tests": ["src/helper/ssg/ssg.test.tsx"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-02T09:37:29Z", "pr": 5501, "pr_url": "https://github.com/honojs/hono/pull/5501"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/helper/ssg/ssg.ts"], "pr_body": "### The author should do the following, if applicable\n\n- [ ] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code", "pr_title": "chore!(ssg): remove deprecated hook options from toSSG"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "2fbb2409fcae6776441066ba0bb5129613f42b21", "candidate_corpus": {"base_commit": "2fbb2409fcae6776441066ba0bb5129613f42b21", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "59dc47d7be4ea39ce3a5423995200a97075e6436", "negative_distractors": ["src/middleware/serve-static/index.ts", "src/request.ts", "src/utils/url.ts"], "related_tests": ["src/hono.test.ts", "src/request.test.ts", "src/utils/url.test.ts"], "root_cause_files": ["src/helper/ssg/middleware.ts", "src/hono-base.ts", "src/middleware/bearer-auth/index.ts", "src/middleware/serve-static/index.ts", "src/request.ts", "src/utils/url.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "9233a608363d1f0c28e85ab3", "metadata": {"confidence": "weak", "created_at": "2026-10-02T09:24:36Z", "evidence": {"implementation_files": ["src/helper/ssg/middleware.ts", "src/hono-base.ts", "src/middleware/bearer-auth/index.ts", "src/middleware/serve-static/index.ts", "src/request.ts", "src/utils/url.ts"], "related_tests": ["src/hono.test.ts", "src/request.test.ts", "src/utils/url.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-02T09:27:44Z", "pr": 5500, "pr_url": "https://github.com/honojs/hono/pull/5500"}, "query": {"changed_file_summary": "6 implementation files and 3 existing test files changed within 9 total files.", "implementation_file_count": 6, "implementation_files": ["src/helper/ssg/middleware.ts", "src/hono-base.ts", "src/middleware/bearer-auth/index.ts", "src/middleware/serve-static/index.ts", "src/request.ts", "src/utils/url.ts"], "pr_body": "### The author should do the following, if applicable\n\n- [ ] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code", "pr_title": "chore!: remove deprecated APIs"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "f23b146afcec63606144cde50b5fbd360dd60238", "candidate_corpus": {"base_commit": "f23b146afcec63606144cde50b5fbd360dd60238", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "e77c7c8eb9fea50a496ba10010063998b55d7a6b", "negative_distractors": [], "related_tests": ["src/helper/route/index.test.ts"], "root_cause_files": ["src/helper/route/index.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "134ca1f4a853fbb4a97f043e", "metadata": {"confidence": "weak", "created_at": "2026-10-02T03:09:27Z", "evidence": {"implementation_files": ["src/helper/route/index.ts"], "related_tests": ["src/helper/route/index.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-16T09:47:27Z", "pr": 5498, "pr_url": "https://github.com/honojs/hono/pull/5498"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["src/helper/route/index.ts"], "pr_body": "`basePath()` from `hono/route` drops a regex param when the next segment of the mount path is not static. `getPattern()` returns `^re$` for such a param, and `basePath()` matches that against the whole rest of the request path. The match fails, so the segment is skipped. The router still matches the request because it falls back to testing the current segment alone.\n\n```ts\nconst sub = new Hono()\nsub.get('/posts/:id', (c) => c.text(basePath(c)))\napp.route('/api/:version{v[0-9]+}', sub)\n// GET /api/v2/posts/123 -> '/api/' (expected '/api/v2')\n```\n\nIf another param follows, the later segments shift too: `/users/:name{[a-z]+}/:group` returns `/users/abc` for `/users/abc/def/...`. `methodNotAllowed` relies on `basePath()`, so with `app.route('/:version{v[0-9]+}', api)` a `POST /v2/posts` returns 404 instead of 405.\n\nThis PR adds the router's single-segment fallback to `basePath()`. Plain params, wildcards and regex params followed by a static segment work as before.\n\n- Ran: `pnpm exec vp test --run --project main src/helper/route src/middleware/method-not-allowed`. 29 passed. The new test fails on main with `'/api/'`.\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code", "pr_title": "fix(helper/route): match regex params in basePath() the same way as the router"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "c9b1148b5b8799758756cbec7c0d1ac187d37f1a", "candidate_corpus": {"base_commit": "c9b1148b5b8799758756cbec7c0d1ac187d37f1a", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "8ec61a7fb6f1961377afd28bbe71f8a2095916ac", "negative_distractors": [], "related_tests": ["tests/test_black.py"], "root_cause_files": ["src/black/files.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "cbfb1533df66d53041652a4c", "metadata": {"confidence": "weak", "created_at": "2026-10-08T11:24:10Z", "evidence": {"implementation_files": ["src/black/files.py"], "related_tests": ["tests/test_black.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-10-10T03:15:14Z", "pr": 5497, "pr_url": "https://github.com/psf/black/pull/5497"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/black/files.py"], "pr_body": "### Description\n\nIf a .gitignore starts with a UTF-8 BOM, Black ignores the first\npattern in it. Git skips the BOM so the pattern still works there,\nbut Black reads it as part of the pattern, so it never matches. So\nBlack ends up formatting files that git ignores.\n\nSome editors and tools on Windows save files with a BOM.\n\nTo reproduce:\n\n```sh\nmkdir demo && cd demo && git init\nmkdir generated\nprintf '\\xef\\xbb\\xbfgenerated/\\n' > .gitignore\nprintf 'x = 1\\n' > generated/models.py\ngit check-ignore generated/models.py # git says it is ignored\nblack --check . # black wants to reformat generated/models.py\n```\n\nThe fix opens .gitignore with utf-8-sig instead of utf-8. That drops\nthe BOM if there is one and reads normal UTF-8 files the same as\nbefore. I added a test with a BOM in both a root and a nested\n.gitignore.\n\n### Checklist - did you ...\n\n- [x] Implement any code style changes under the `--preview` style, following the stability policy?\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests if necessary?\n- [x] Add new / update outdated documentation?", "pr_title": "Skip UTF-8 BOM when reading .gitignore"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "30664d8f17b29658aa72e44a1bfe23eede12db99", "candidate_corpus": {"base_commit": "30664d8f17b29658aa72e44a1bfe23eede12db99", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "f4f6cd9becdafb8e88dfff171ad4bb91427864c8", "negative_distractors": [], "related_tests": ["tests/test_ipynb.py"], "root_cause_files": ["src/black/handle_ipynb_magics.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "59624cf03cf3be878401198a", "metadata": {"confidence": "weak", "created_at": "2026-10-04T18:11:02Z", "evidence": {"implementation_files": ["src/black/handle_ipynb_magics.py"], "related_tests": ["tests/test_ipynb.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-10-05T03:46:22Z", "pr": 5481, "pr_url": "https://github.com/psf/black/pull/5481"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/black/handle_ipynb_magics.py"], "pr_body": "### Description\n\nWhen a notebook cell has a magic assignment that is longer than the line length, Black\nwraps it in parentheses. For example this cell:\n\n```python\ninstalled_packages_in_this_environment = !pip list --format=freeze --disable-pip-version-check\n```\n\nbecomes:\n\n```python\ninstalled_packages_in_this_environment = (\n !pip list --format=freeze --disable-pip-version-check\n)\n```\n\nIPython does not accept a magic inside parentheses, so the cell now fails with\n`SyntaxError: invalid syntax` when you run it. Black exits with 0, and later runs of\n`black --check` also pass because Black skips the broken cell.\n\nThe reason is that Black formats the cell with each magic replaced by a placeholder\nstring. The placeholder can be wrapped like any other string, and the safety check only\nsees the placeholder version, so it does not notice the problem.\n\nThe fix is in `unmask_cell`. After the magics are put back, it masks the cell again and\nchecks that IPython still finds the same magics. If it does not, the cell is left\nunchanged, the same way Black already skips cells it cannot format safely.\n\nI added tests for a long `!` assignment, a long `%timeit -o` assignment, an indented one,\nand a direct test for `unmask_cell`. All of them fail without the fix.\n\n### Checklist - did you ...\n\n- [x] Implement any code style changes under the `--preview` style, following the stability policy?\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests if necessary?\n- [x] Add new / update outdated documentation?", "pr_title": "Fix long notebook magic assignments being wrapped in parentheses"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "ee05651742abc47ec807c0fb34247ac6f4f3c5fc", "candidate_corpus": {"base_commit": "ee05651742abc47ec807c0fb34247ac6f4f3c5fc", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "97fb59f06a076fa34c68b2922b4d3da583adfa90", "negative_distractors": [], "related_tests": ["tests/test_black.py"], "root_cause_files": ["src/black/__init__.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "1d00e018980703687b2eb669", "metadata": {"confidence": "weak", "created_at": "2026-10-03T07:37:37Z", "evidence": {"implementation_files": ["src/black/__init__.py"], "related_tests": ["tests/test_black.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-10-05T17:32:32Z", "pr": 5476, "pr_url": "https://github.com/psf/black/pull/5476"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/black/__init__.py"], "pr_body": "### Description\n\nFixes #5474\n\nWhen black runs with `--line-ranges` it still saves the file in the cache as if the whole file was formatted\n\nAfter that a normal `black --check` trusts the cache and exits 0 even though the rest of the file is not formatted and a plain `black` run skips the file too\n\nThis change skips the cache write in `reformat_one` when line ranges are used\n\nReading the cache stays the same since a fully formatted file is still fine for any range\n\nI added a test that covers both the format case and the check case\n\n### Checklist - did you ...\n\n- [x] Implement any code style changes under the `--preview` style, following the stability policy?\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests if necessary?\n- [x] Add new / update outdated documentation?", "pr_title": "Fix check passing after a line ranges run"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "18331a905e2415f7f73038357f2eec354123f7a6", "candidate_corpus": {"base_commit": "18331a905e2415f7f73038357f2eec354123f7a6", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "c3053ccf14f1c4c70a0c2888eed6121b9f6c8f95", "negative_distractors": [], "related_tests": ["src/middleware/etag/index.test.ts"], "root_cause_files": ["src/middleware/etag/index.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "d3c95f27db8c13657088b907", "metadata": {"confidence": "weak", "created_at": "2026-09-28T16:20:17Z", "evidence": {"implementation_files": ["src/middleware/etag/index.ts"], "related_tests": ["src/middleware/etag/index.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-30T08:36:41Z", "pr": 5475, "pr_url": "https://github.com/honojs/hono/pull/5475"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["src/middleware/etag/index.ts"], "pr_body": "Since the etag middleware compares header name converted to lower case, it did not match mixed-case header names specified in `retainedHeader` option, thus they were never retained.\nFixed by converting all header names in the option to lowercase beforehand.\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code", "pr_title": "fix(etag): correctly match mixed-case header name in retainedHeader option"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "994ef7eeb18172178552daa1f36f001d156ad583", "candidate_corpus": {"base_commit": "994ef7eeb18172178552daa1f36f001d156ad583", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "e1c478359c087b76a6c4830a84c7e78ac93d8a6c", "negative_distractors": [], "related_tests": ["tests/test_black.py"], "root_cause_files": ["src/black/files.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "3416a0473f5671c22d70692f", "metadata": {"confidence": "weak", "created_at": "2026-10-02T11:22:06Z", "evidence": {"implementation_files": ["src/black/files.py"], "related_tests": ["tests/test_black.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-10-03T21:30:52Z", "pr": 5471, "pr_url": "https://github.com/psf/black/pull/5471"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/black/files.py"], "pr_body": "### Description\n\nFixes #5470\n\nWhen a file path has `..` in it `--force-exclude` does not match it so the excluded file still gets formatted. For example with `force-exclude = \"^/generated/\"` running `black ../generated/gen.py` from `src/` reformats `generated/gen.py`. The same happens with `--stdin-filename`\n\n`best_effort_relative_path` used `path.absolute()` which keeps the `..` so the regex was checked against `/src/../generated/gen.py` and not `/generated/gen.py`\n\nThis PR collapses the `..` with `os.path.normpath` before the check. It does not resolve symlinks so the current symlink behaviour stays the same. If a symlink makes the collapsed path leave the project root the path is kept as given so that case works like before\n\nI added two tests. One for `..` paths (a file path and stdin) and one for the symlink case\n\n### Checklist - did you ...\n\n- [x] Implement any code style changes under the `--preview` style, following the stability policy?\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests if necessary?\n- [x] Add new / update outdated documentation?", "pr_title": "Fix --force-exclude for paths containing .."}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "f3d5e8856244eb5faf9e1322834ca1639134d971", "candidate_corpus": {"base_commit": "f3d5e8856244eb5faf9e1322834ca1639134d971", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "72f0d8d58e20547c25370a97191765a9ca0e1d9b", "negative_distractors": [], "related_tests": ["adapters/netlify/src/conninfo.test.ts"], "root_cause_files": ["adapters/netlify/src/conninfo.ts", "adapters/netlify/src/index.ts", "adapters/netlify/src/mod.ts"], "root_cause_symbols": [], "supporting_files": ["adapters/netlify/README.md", "adapters/netlify/deno.json", "adapters/netlify/tsconfig.json", "docs/MAINTAINING.md"]}, "id": "78dc3d51baac618e5d5902f5", "metadata": {"confidence": "weak", "created_at": "2026-09-28T08:35:01Z", "evidence": {"implementation_files": ["adapters/netlify/src/conninfo.ts", "adapters/netlify/src/index.ts", "adapters/netlify/src/mod.ts"], "related_tests": ["adapters/netlify/src/conninfo.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-28T08:38:04Z", "pr": 5468, "pr_url": "https://github.com/honojs/hono/pull/5468"}, "query": {"changed_file_summary": "3 implementation files and 1 existing test files changed within 8 total files.", "implementation_file_count": 3, "implementation_files": ["adapters/netlify/src/conninfo.ts", "adapters/netlify/src/index.ts", "adapters/netlify/src/mod.ts"], "pr_body": "### The author should do the following, if applicable\n\n- [ ] Add tests\n- [ ] Run tests\n- [ ] `pnpm run check:fix` to format and lint the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code", "pr_title": "feat(adapters/netlify): publish to JSR"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "1e6d48e43718ca534da4da600c9f591e949b2c17", "candidate_corpus": {"base_commit": "1e6d48e43718ca534da4da600c9f591e949b2c17", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "93e5c8204c0340403c925a3bf7b747bf7817aaab", "negative_distractors": [], "related_tests": ["tests/test_black.py"], "root_cause_files": ["src/black/strings.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "88e2e7a4c130a535510e0c0b", "metadata": {"confidence": "weak", "created_at": "2026-09-30T22:39:08Z", "evidence": {"implementation_files": ["src/black/strings.py"], "related_tests": ["tests/test_black.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-10-04T01:03:44Z", "pr": 5461, "pr_url": "https://github.com/psf/black/pull/5461"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/black/strings.py"], "pr_body": "### Description\n\nFixes #5460.\n\nDocstring reindentation used `str.splitlines()`, which also splits on form feed, vertical tab, and Unicode separators. Those characters could become newlines and change the docstring value. Split only on LF, CRLF, and CR, matching Python's parser.\n\nThe regressions compare the docstring value directly and check second-pass stability; Black's AST equivalence check normalizes away the difference. A companion test preserves real line-break handling.\n\nThe latest follow-up corrects the changelog reference from issue #5460 to PR #5461. The workflow's PR-number regex and `git diff --check` pass locally. Product tests were not rerun for this changelog-only follow-up.\n\n### Checklist - did you ...\n\n- [x] Implement any code style changes under the `--preview` style, following the stability policy? — The documented exception for unintended formatting bugs applies; this preserves string contents.\n- [x] Add an entry in `CHANGES.md` if necessary? — Stable style, #5461.\n- [x] Add / update tests if necessary? — Separator preservation and real line-break regressions.\n- [x] Add new / update outdated documentation? — No advertised style change; the contributing guidance exempts unintended formatting fixes.", "pr_title": "Do not split a docstring on non-newline characters"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "5f31392d724cf98c9e48a3de119a55284583ad5f", "candidate_corpus": {"base_commit": "5f31392d724cf98c9e48a3de119a55284583ad5f", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "90d02fb1645c12a65d27f39594d2129db2065ba7", "negative_distractors": [], "related_tests": ["src/context.test.ts", "src/middleware/serve-static/index.test.ts"], "root_cause_files": ["src/context.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "ea8e1c8ba11f26eb64060540", "metadata": {"confidence": "weak", "created_at": "2026-09-25T07:32:49Z", "evidence": {"implementation_files": ["src/context.ts"], "related_tests": ["src/context.test.ts", "src/middleware/serve-static/index.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-25T07:35:52Z", "pr": 5446, "pr_url": "https://github.com/honojs/hono/pull/5446"}, "query": {"changed_file_summary": "1 implementation files and 2 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/context.ts"], "pr_body": "`c.body()` accepts a `Blob` at runtime but `Data` did not list it, so `serve-static`'s `getContent` could not be typed to return one.\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code", "pr_title": "fix(types): allow returning a Blob as a response body"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "8d5a2d9f49378d7abe2eb632df1601818de8c24e", "candidate_corpus": {"base_commit": "8d5a2d9f49378d7abe2eb632df1601818de8c24e", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "a7c2368b7e183f1a42ed51219c86d453067f78cb", "negative_distractors": [], "related_tests": ["tests/test_blackd.py"], "root_cause_files": ["src/blackd/__init__.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "0c27018771e7381d68b1cd0d", "metadata": {"confidence": "weak", "created_at": "2026-09-27T05:08:24Z", "evidence": {"implementation_files": ["src/blackd/__init__.py"], "related_tests": ["tests/test_blackd.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-09-30T03:05:45Z", "pr": 5441, "pr_url": "https://github.com/psf/black/pull/5441"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/blackd/__init__.py"], "pr_body": "### Description\n\nIn blackd, comma-separated lists in `X-Python-Variant` with standard whitespace after commas (such as `py3.8, py3.9` or `3.8, py3.9`) and `pyi` with surrounding whitespace failed with HTTP 400 (`Invalid value for X-Python-Variant: expected e.g. '3.7', 'py3.5'`).\n\nFor each entry, `parse_python_variant_header` checks `version.startswith(\"py\")` and strips `\"py\"`, but without stripping whitespace first, an entry like `\" py3.9\"` retains its leading space, failing `.startswith(\"py\")`. It then extracts `\" py3\"` as `major_str`, which fails `int()` parsing and raises `InvalidVariantHeader`. Similarly, `\" pyi \"` failed the exact equality check against `\"pyi\"`.\n\nThis fix strips whitespace from `value` and from each `version` token during iteration, matching the stripping pattern already used for `X-Enable-Unstable-Feature`.\n\nTests added to `test_blackd_invalid_python_variant`, `test_blackd_pyi`, and `test_blackd_python_variant` covering whitespace variations.\n\n### Checklist - did you ...\n\n- [x] Implement any code style changes under the `--preview` style, following the stability policy? (N/A, this change is in blackd only)\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests if necessary?\n- [x] Add new / update outdated documentation? (N/A, makes blackd accept standard whitespace)", "pr_title": "Allow whitespace around versions in blackd X-Python-Variant header"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "8d5a2d9f49378d7abe2eb632df1601818de8c24e", "candidate_corpus": {"base_commit": "8d5a2d9f49378d7abe2eb632df1601818de8c24e", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "dd76ff8d6fee1d6b3a90216cf934e364b8d66625", "negative_distractors": [], "related_tests": ["tests/test_black.py"], "root_cause_files": ["src/black/__init__.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "1d68dbbaf34304eae4bc7277", "metadata": {"confidence": "weak", "created_at": "2026-09-26T09:25:13Z", "evidence": {"implementation_files": ["src/black/__init__.py"], "related_tests": ["tests/test_black.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-09-29T21:57:09Z", "pr": 5438, "pr_url": "https://github.com/psf/black/pull/5438"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/black/__init__.py"], "pr_body": "### Description\n\nWith `-x` / `--skip-source-first-line`, `format_file_in_place` reads the skipped first line as raw bytes and prepends it to the formatted code. It then writes the result through `open(..., newline=newline)`, which turns every `\\n` into the file's newline. On a CRLF file the header already ends in `\\r\\n`, so it comes out as `\\r\\r\\n`. Only the first line is affected, and only when the rest of the file changes.\n\n`-x` mirrors Python's `-x` option, which exists for the Windows batch-file trick, so CRLF files are exactly where it gets used.\n\n```console\n$ printf 'hdr ((\\r\\nx = 1\\r\\n' > t.py\n$ black -q -x t.py; od -c t.py\n0000000 h d r ( ( \\r \\r \\n x = 1 \\r \\n\n```\n\n`--diff` goes through the same newline translation, so the header context line in the diff also shows up as `hdr ((\\r\\r\\n`.\n\nThe fix gives the header a plain `\\n` ending when it already ends in the file's newline, so the translation turns it back into the original ending. The other cases stay as they were, including `test_skip_source_first_line_when_mixing_newlines` (a CRLF header followed by LF code).\n\n### Checklist - did you ...\n\n- [x] Implement any code style changes under the `--preview` style, following the stability policy?\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests if necessary?\n- [x] Add new / update outdated documentation?", "pr_title": "Keep the CRLF ending of the line skipped by `--skip-source-first-line`"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "77c0cae18bcc82257882afc7bbb9a5cd95cba16c", "candidate_corpus": {"base_commit": "77c0cae18bcc82257882afc7bbb9a5cd95cba16c", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "6e940882526b846e4487c5760f0127739abf9902", "negative_distractors": [], "related_tests": ["tests/data/cases/line_ranges_diff_edge_case.py", "tests/test_black.py", "tests/test_ranges.py"], "root_cause_files": ["src/black/ranges.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "2d542d292f74e037d72663d3", "metadata": {"confidence": "weak", "created_at": "2026-09-25T19:36:16Z", "evidence": {"implementation_files": ["src/black/ranges.py"], "related_tests": ["tests/data/cases/line_ranges_diff_edge_case.py", "tests/test_black.py", "tests/test_ranges.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-10-05T18:02:20Z", "pr": 5436, "pr_url": "https://github.com/psf/black/pull/5436"}, "query": {"changed_file_summary": "1 implementation files and 3 existing test files changed within 5 total files.", "implementation_file_count": 1, "implementation_files": ["src/black/ranges.py"], "pr_body": "### Description\n\nRelated to #4052 and #4033. When unchanged lines have identical text on both sides of a selected range, `SequenceMatcher` can align those lines at the wrong positions. Formatting lines 2–3 in a five-line example then formats line 5 as well. This anchors identical prefix and suffix lines before diffing the middle, so the second pass keeps the selected range at its original position. The existing regression fixture now expects only the selected lines to change. For disjoint ranges, when the first pass preserves line count and every unselected line is byte-for-byte unchanged, the original ranges can be reused without an ambiguous text diff.\n\nThe new regression also covers disjoint ranges selecting lines 1 and 3 of three identical unformatted lines; line 2 now stays untouched. The `--line-ranges` stability check remains disabled, and this is not a complete replacement for #4052's diff algorithm, so the existing documentation warning remains in place.\n\nTests: 45 focused tests passed; Black formatting and all pre-commit hooks for changed files passed. The initial full Windows `tox -e py313 -- -n 0` run had 505 passes and three failures: two color-diff tests also fail on the unmodified base in this environment, and the third was the old fixture expectation updated in this PR. After that update, the non-Jupyter suite passed 507 selected tests with one skip; two baseline-failing color tests were excluded, and one color-control test excluded by the name filter passed separately. The optional Jupyter stage passed 75 tests. This change was prepared with Codex assistance; the diff and test results were checked before submission.\n\n### Checklist - did you ...\n\n- [x] Follow the stability policy? This changes line selection, not Black's formatting style.\n- [x] Add an en\n...[truncated]", "pr_title": "Keep repeated unchanged lines outside selected ranges"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "8dcd52b92beada28962e818bdca8a137a6beb656", "candidate_corpus": {"base_commit": "8dcd52b92beada28962e818bdca8a137a6beb656", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "d54720da80134a180f5fe2dd98a7676cfc8f08b4", "negative_distractors": [], "related_tests": ["src/middleware/serve-static/index.test.ts"], "root_cause_files": ["src/middleware/serve-static/index.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "ac2263e580ff304ee16c4f92", "metadata": {"confidence": "weak", "created_at": "2026-09-24T02:31:59Z", "evidence": {"implementation_files": ["src/middleware/serve-static/index.ts"], "related_tests": ["src/middleware/serve-static/index.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-16T09:42:50Z", "pr": 5436, "pr_url": "https://github.com/honojs/hono/pull/5436"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["src/middleware/serve-static/index.ts"], "pr_body": "With `precompressed: true`, `serveStatic` splits `Accept-Encoding` on commas and compares the raw tokens. An encoding sent with a q-value, such as `gzip;q=1.0`, never matches, so the uncompressed file is served even when a precompressed one exists.\n\nThis parses the header with `parseAccept`, as the compress middleware does, and skips encodings rejected with `q=0`. The preference order (br > zstd > gzip) is unchanged.\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `pnpm run format:fix && pnpm run lint:fix` to format the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code", "pr_title": "fix(serve-static): respect q-values in Accept-Encoding for precompressed files"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "8d5a2d9f49378d7abe2eb632df1601818de8c24e", "candidate_corpus": {"base_commit": "8d5a2d9f49378d7abe2eb632df1601818de8c24e", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "aec65659c6a803c5fa908667748c585403ab960a", "negative_distractors": [], "related_tests": ["tests/data/cases/preview_long_strings.py"], "root_cause_files": ["src/black/linegen.py", "src/black/mode.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md", "docs/the_black_code_style/future_style.md", "src/black/resources/black.schema.json", "tests/data/cases/preview_keep_dict_keys_with_operators.py"]}, "id": "6cb0e3a62700633c3d4229a3", "metadata": {"confidence": "weak", "created_at": "2026-09-25T17:55:38Z", "evidence": {"implementation_files": ["src/black/linegen.py", "src/black/mode.py"], "related_tests": ["tests/data/cases/preview_long_strings.py"], "signals": ["same_pr_changed_implementation_and_tests", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-10-01T14:18:20Z", "pr": 5435, "pr_url": "https://github.com/psf/black/pull/5435"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 7 total files.", "implementation_file_count": 2, "implementation_files": ["src/black/linegen.py", "src/black/mode.py"], "pr_body": "### Summary of Changes\n\n When a dictionary key contains operators (such as `+`, `-`, or `%`) and the line exceeds the line length, `delimiter_split`\n would previously split inside the key at the operator instead of allowing the dictionary value to wrap or explode onto a new line.\n\n This PR introduces the preview style feature `keep_dict_keys_with_operators`:\n - Checks if a line is a dictionary entry whose highest-priority delimiters are located on the key side (before the bracket depth-0 colon).\n - Defers `delimiter_split` to `right_hand_split` when the key and the opening parenthesis/bracket of the value fit within the line length limit.\n - Leaves keys that are genuinely too long by themselves to split inside the key as before.\n - Adds comprehensive preview tests, updates schema, documentation in `future_style.md`, and changelog in `CHANGES.md`.\n\n ### Example\n\n ```python\n # Before\n tests = {\n Timestamp(\"2014-07-04 15:00\")\n + Nano(5): this_is_a_very_long_function(\"2014-07-04 16:00\"),\n }\n\n # After (with --preview)\n tests = {\n Timestamp(\"2014-07-04 15:00\") + Nano(5): this_is_a_very_long_function(\n \"2014-07-04 16:00\"\n ),\n }", "pr_title": "Keep dictionary keys with operators together in preview (#3442)"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "2b96e280653fd79f593c942191d8614ca6ce39e6", "candidate_corpus": {"base_commit": "2b96e280653fd79f593c942191d8614ca6ce39e6", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "b30c97e31acb233ef7e6bb8fd2cfe88279c9b419", "negative_distractors": [], "related_tests": ["tests/test_blackd.py"], "root_cause_files": ["src/blackd/__init__.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "3ca886c33d938881a6761612", "metadata": {"confidence": "weak", "created_at": "2026-09-23T09:46:37Z", "evidence": {"implementation_files": ["src/blackd/__init__.py"], "related_tests": ["tests/test_blackd.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-09-24T16:41:38Z", "pr": 5428, "pr_url": "https://github.com/psf/black/pull/5428"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/blackd/__init__.py"], "pr_body": "### Description\n\nThe blackd docs say an invalid value in any of the request headers gets an `HTTP 400` response that names the problematic header. `X-Python-Variant` breaks that for three kinds of value:\n\n- an empty value;\n- a bare `py`;\n- a list with an empty entry, such as a trailing comma (`3.6,`) or a doubled comma (`py3.6,,py3.7`).\n\nFor each entry, `parse_python_variant_header` strips an optional `py` prefix and then reads `version[0]` outside its `try` block. An empty entry therefore raises `IndexError`, which escapes the header validation, so the handler logs a traceback and answers with `HTTP 500` and the body `string index out of range`.\n\nThe fix rejects an empty entry with the same `InvalidVariantHeader` the function already raises for other malformed values. The request now gets the documented 400: `Invalid value for X-Python-Variant: expected e.g. '3.7', 'py3.5'`.\n\nThe four values above are added to `test_blackd_invalid_python_variant`. The test fails with `500 != 400` before the change and passes after it.\n\n### Checklist - did you ...\n\n- [x] Implement any code style changes under the `--preview` style, following the stability policy? (N/A, this change is in blackd only)\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests if necessary?\n- [x] Add new / update outdated documentation? (N/A, this makes blackd match its existing docs)", "pr_title": "Return HTTP 400 for an empty `X-Python-Variant` entry in blackd"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "5f4516d267e705f73a648a713cf1b25cb0c9d019", "candidate_corpus": {"base_commit": "5f4516d267e705f73a648a713cf1b25cb0c9d019", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "42047e102f6df3847a14524c875e02b00a8f0c6b", "negative_distractors": [], "related_tests": ["tests/data/cases/preview_return_annotation_brackets_string.py"], "root_cause_files": ["src/black/linegen.py", "src/black/trans.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "ebb016c995e01568d6122b03", "metadata": {"confidence": "weak", "created_at": "2026-09-22T11:04:35Z", "evidence": {"implementation_files": ["src/black/linegen.py", "src/black/trans.py"], "related_tests": ["tests/data/cases/preview_return_annotation_brackets_string.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-09-24T21:52:38Z", "pr": 5427, "pr_url": "https://github.com/psf/black/pull/5427"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["src/black/linegen.py", "src/black/trans.py"], "pr_body": "### Description\n\nFixes #3926.\nCloses #5404 \nLong stringified return annotations were split when a function had no parameters, but adding parameters caused only the parameter list to split, leaving the annotation over the configured line length. This routes direct stringified return annotations through the right-hand-side transformation and preserves the function colon when wrapping and splitting the string.\n\n### Checklist - did you ...\n\n- [x] Implement the style change under `--unstable`, following the stability policy?\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests?\n- [x] Add new / update outdated documentation? No user documentation change is needed.\n\nValidation:\n- `pytest tests/test_format.py -q` (243 passed)\n- `pytest tests/test_trans.py -q` (1 passed)\n- repository pre-commit hooks (isort, flake8, mypy, whitespace checks)\n- `git diff --check`", "pr_title": "Fix splitting stringified return annotations with parameters"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "28e8572cd265b4da1160ce6cd51919bb70516e2c", "candidate_corpus": {"base_commit": "28e8572cd265b4da1160ce6cd51919bb70516e2c", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "de310ac063febf3e7b73f6206142d0e88800661f", "negative_distractors": [], "related_tests": ["src/adapter/lambda-edge/handler.test.ts"], "root_cause_files": ["src/adapter/lambda-edge/handler.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "788b8d40360ae8dde04ff8e7", "metadata": {"confidence": "weak", "created_at": "2026-09-21T16:31:35Z", "evidence": {"implementation_files": ["src/adapter/lambda-edge/handler.ts"], "related_tests": ["src/adapter/lambda-edge/handler.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-22T05:50:22Z", "pr": 5426, "pr_url": "https://github.com/honojs/hono/pull/5426"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["src/adapter/lambda-edge/handler.ts"], "pr_body": "`lambda-edge` still uses the old content-type check, so binary types such as `application/vnd.openxmlformats-officedocument.wordprocessingml.document` are treated as text because `openxmlformats` contains `xml`. `createResult()` then reads the body with `res.text()`.\n\n`aws-lambda` has the updated check from #4469 and #5424. This applies the same check and test cases to `lambda-edge`. Six of those test cases fail with the current `lambda-edge` implementation.\n\nRelated: #4900, #5412.\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `bun run format:fix && bun run lint:fix` to format the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code", "pr_title": "fix(lambda-edge): sync content type detection with aws-lambda"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "acd6198877ced2d8126b9b3958bb17f4a65ef0d1", "candidate_corpus": {"base_commit": "acd6198877ced2d8126b9b3958bb17f4a65ef0d1", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "da22d4390519b10d03d3c8ab4697a0770cce5e76", "negative_distractors": [], "related_tests": ["tests/test_black.py"], "root_cause_files": ["src/black/__init__.py", "src/black/files.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "0c90cc61a858504727268032", "metadata": {"confidence": "weak", "created_at": "2026-09-17T02:10:18Z", "evidence": {"implementation_files": ["src/black/__init__.py", "src/black/files.py"], "related_tests": ["tests/test_black.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-09-21T22:40:59Z", "pr": 5411, "pr_url": "https://github.com/psf/black/pull/5411"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["src/black/__init__.py", "src/black/files.py"], "pr_body": "### Description\n\nFixes #2516\n\n**Bug:** Calling `black.reformat_code()` / `black.format_stdin_to_stdout()` from a Jupyter notebook fails with `AttributeError: 'OutStream' object has no attribute 'buffer'`. The diff output of `format_file_in_place()` (`WriteBack.DIFF` / `COLOR_DIFF`) has the same problem.\n\n**Root cause:** Both functions wrap `sys.stdout.buffer` in `io.TextIOWrapper` so they can control the encoding and newline translation. `TextIOBase.buffer` is [not part of the `TextIOBase` API](https://docs.python.org/3/library/io.html#io.TextIOBase.buffer) and ipykernel's `OutStream` doesn't have it. `format_stdin_to_stdout()` builds that wrapper in its `finally` block for every `write_back` mode, so even `--check`-style calls crash. The issue thread notes that just using `getattr(sys.stdout, \"buffer\", sys.stdout)` doesn't work either, because `OutStream.write()` only accepts `str`.\n\n**Change:** Both code paths now go through a small `_write_to_stdout()` helper:\n\n- If `sys.stdout` has a `buffer`, it does what the code did before: wraps it in `io.TextIOWrapper(..., write_through=True)`, wraps it for Windows colors where needed, writes, then detaches.\n- If there is no `buffer`, it writes text straight to `sys.stdout`. It does the `\\n` -> `newline` translation itself (this is what `TextIOWrapper` would do, and the content has already been normalized to `\\n` at that point) and leaves encoding to the stream. The stream is never detached or closed.\n\n`format_stdin_to_stdout()` now only touches stdout when `write_back` is `YES`/`DIFF`/`COLOR_DIFF`. `wrap_stream_for_windows()`'s annotation is widened from `io.TextIOWrapper` to `TextIO` so it accepts `sys.stdout`. At runtime it already accepted any stream.\n\n**Tests:** I added three tests that patch `sys.stdout` with an `io.Strin\n...[truncated]", "pr_title": "Don't require sys.stdout.buffer when writing formatted output or diffs"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "b5b1eb6f60ce9febc473c6cb49f935954d108678", "candidate_corpus": {"base_commit": "b5b1eb6f60ce9febc473c6cb49f935954d108678", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "cf8560b1f43014986662ab4e717da29e98b8c651", "negative_distractors": [], "related_tests": ["tests/test_black.py"], "root_cause_files": ["src/black/__init__.py", "src/black/report.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md", "action.yml", "docs/integrations/github_actions.md"]}, "id": "804b68475f2a7fe579245698", "metadata": {"confidence": "weak", "created_at": "2026-09-16T14:02:41Z", "evidence": {"implementation_files": ["src/black/__init__.py", "src/black/report.py"], "related_tests": ["tests/test_black.py"], "signals": ["same_pr_changed_implementation_and_tests", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-10-03T23:08:26Z", "pr": 5408, "pr_url": "https://github.com/psf/black/pull/5408"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 6 total files.", "implementation_file_count": 2, "implementation_files": ["src/black/__init__.py", "src/black/report.py"], "pr_body": "#### Description:\n\n ## Summary of changes\n\n - Added `outputs.is_formatted` to `action.yml` and attached `id: black` to the composite execution step.\n - Updated `action/main.py` to write `is_formatted=true` / `is_formatted=false` to `$GITHUB_OUTPUT` based on Black's exit code\n and report output.\n - Documented the new output in `docs/integrations/github_actions.md`.\n - Closes #3526.\n\n ## Test Plan\n\n - Ran `mypy action/main.py` (clean, 0 errors).\n - Ran `pytest tests/test_docs.py` (passed).", "pr_title": "Add is_formatted output to GitHub Action (#3526)"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "2772c28f7a8304edec67a9eface937841cee1f74", "candidate_corpus": {"base_commit": "2772c28f7a8304edec67a9eface937841cee1f74", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "e92826579e5da60671a01d73f0ad2bf32a834be8", "negative_distractors": [], "related_tests": ["runtime-tests/workerd/index.test.ts", "src/middleware/logger/index.test.ts", "src/utils/color.test.ts"], "root_cause_files": ["runtime-tests/workerd/index.ts", "src/middleware/logger/index.ts", "src/utils/color.ts"], "root_cause_symbols": [], "supporting_files": ["docs/MIGRATION.md"]}, "id": "0686096ad7f7af6c5c57b7e7", "metadata": {"confidence": "weak", "created_at": "2026-09-15T19:06:19Z", "evidence": {"implementation_files": ["runtime-tests/workerd/index.ts", "src/middleware/logger/index.ts", "src/utils/color.ts"], "related_tests": ["runtime-tests/workerd/index.test.ts", "src/middleware/logger/index.test.ts", "src/utils/color.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-07T06:31:50Z", "pr": 5402, "pr_url": "https://github.com/honojs/hono/pull/5402"}, "query": {"changed_file_summary": "3 implementation files and 3 existing test files changed within 7 total files.", "implementation_file_count": 3, "implementation_files": ["runtime-tests/workerd/index.ts", "src/middleware/logger/index.ts", "src/utils/color.ts"], "pr_body": "The logger currently awaits color detection on every outgoing log line, including a dynamic `cloudflare:workers` import on Workers. Pass `c.env` to `getColorEnabled(env?)` so color detection and formatting are synchronous and the middleware only awaits `next()`.\n\nCheck bindings on each call, then fall back to the existing Deno/process detection. Remove the async helper and the import workarounds; the two production files shrink by 41 lines.\n\n**Breaking change for v5:** remove `getColorEnabledAsync()` from `hono/utils/color`. Callers should use `getColorEnabled()`, passing `c.env` or Worker bindings explicitly on Cloudflare. Includes a migration note.\n\nRelated to #5106. Draft against `main` because there is no v5 branch yet.\n\n### Validation\n\n- `env -u NO_COLOR bun run test`: 5,161 passed, 44 skipped, including Workers tests with `disallow_importable_env`.\n- `env -u NO_COLOR bun run test:bun`: 26 passed.\n- Deno smoke check for color detection and logger bindings.\n- Build, formatting, lint, and EditorConfig checks passed. Lint and package validation report existing warnings outside the changed files.\n\n`NO_COLOR` was unset for test commands because the local shell sets it to `1`; the tests cover it explicitly.\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] Format and lint the code\n- [x] Add JSDoc to document the code", "pr_title": "refactor(logger)!: make color detection synchronous for v5"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "f5a53463ad2ff791fc02418b645750ce75a260ad", "candidate_corpus": {"base_commit": "f5a53463ad2ff791fc02418b645750ce75a260ad", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "afb2068c1c53a530528ac5f237e245793dd03c07", "negative_distractors": [], "related_tests": ["src/middleware/combine/index.test.ts"], "root_cause_files": ["src/middleware/combine/index.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "caaac3ced828833c2d0cfca4", "metadata": {"confidence": "weak", "created_at": "2026-09-13T17:45:27Z", "evidence": {"implementation_files": ["src/middleware/combine/index.ts"], "related_tests": ["src/middleware/combine/index.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-30T08:48:22Z", "pr": 5391, "pr_url": "https://github.com/honojs/hono/pull/5391"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["src/middleware/combine/index.ts"], "pr_body": "A middleware that short-circuits returns a `Response` without calling `next()`. Inside `some()` that Response is dropped, so the context is never finalized and the request 500s.\n\n```ts\nimport { some, every } from 'hono/combine'\n\n// a validator-style middleware: returns a Response, never calls next()\nconst validator = async (c) => c.json({ error: 'bad request' }, 400)\n\nconst a = new Hono()\na.use('/', some(validator, async (c, next) => await next()))\na.get('/', (c) => c.text('HANDLER'))\nawait a.request('/') // 500 Internal Server Error\n\nconst b = new Hono()\nb.use('/', every(validator, async (c, next) => await next()))\nb.get('/', (c) => c.text('HANDLER'))\nawait b.request('/') // 400 {\"error\":\"bad request\"}\n```\n\nstderr on the `some()` request:\n\n```\nError: Context is not finalized. Did you forget to return a Response object or `await next()`?\n```\n\n`every()` gives the right answer on the identical input.\n\n### Cause\n\n`some()` matches the handler's result against `true` and `false`, then `break`s without keeping it:\n\n```ts\nconst result = await handler(c, wrappedNext)\nif (result === true && !c.finalized) {\n await wrappedNext()\n} else if (result === false) {\n lastError = new Error('No successful middleware found')\n continue\n}\nlastError = undefined\nbreak // a Response lands here and is lost\n```\n\n`c.json()` and `c.text()` do not assign `c.res`, so nothing finalizes the context.\n\nThis is the same report as #3441, which fixed it for `every()`: *\"When using `every` middleware to compose middlewares that short-circuits the chain (i.e. return a `Response` object, like e.g. `zod-validator`, but I had also issues with e.g. `cors` with OPTIONS requests) and, as a result, don't call `next()`, it was throwing an error `Error: Context is not finalized...`\"*. `some()` was not\n...[truncated]", "pr_title": "fix(combine): return a Response from a short-circuiting middleware in some()"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "2b96e280653fd79f593c942191d8614ca6ce39e6", "candidate_corpus": {"base_commit": "2b96e280653fd79f593c942191d8614ca6ce39e6", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "8d5a2d9f49378d7abe2eb632df1601818de8c24e", "negative_distractors": [], "related_tests": ["tests/test_black.py"], "root_cause_files": ["src/black/__init__.py", "src/black/files.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "da21dd58f4cc79ba48b0e495", "metadata": {"confidence": "weak", "created_at": "2026-09-03T05:40:02Z", "evidence": {"implementation_files": ["src/black/__init__.py", "src/black/files.py"], "related_tests": ["tests/test_black.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-09-24T22:50:59Z", "pr": 5386, "pr_url": "https://github.com/psf/black/pull/5386"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["src/black/__init__.py", "src/black/files.py"], "pr_body": "## Description\n\nCloses #5379\nCloses #5422\n\nFixes the crash in #5379: when the given sources share no common parent directory — for example, they live on different drives on Windows — `find_project_root` raised `ValueError: max() iterable argument is empty` during CLI startup, before any file was formatted.\n\nThis implements the option @cobaltt7 preferred in the issue discussion: treat the situation as *no config found* rather than an error.\n\n- `find_project_root` returns `(None, None)` when the sources' parent sets do not intersect, instead of crashing.\n- No project-level `pyproject.toml` is discovered in that case; the user-level config applies as usual, otherwise Black's defaults are used.\n- A warning is printed (`No project root could be identified: ... Pass --config ... or --quiet ...`), silenced by passing `--config` explicitly or by `--quiet`. (The issue comment mentioned a `--silent` flag; Black's closest equivalent is `--quiet`.)\n- Formatting continues.\n\nOne structural point that the \"no config found\" framing alone doesn't cover: the project root is not used only for config discovery — it also anchors gitignore handling, `--exclude`/`--force-exclude` matching, and the symlink-outside-root guard in `get_sources`/`gen_python_files`, and `child.relative_to(root)` can never work across drives with a single root. So when no common root exists, this PR falls back to a **per-source root**: each top-level source (its directory, for files) acts as the root for its own discovery/exclusion handling. Same-drive invocations are completely unchanged.\n\nNote #5385 implements the alternative route from the same comment (a usage error). Whichever route the maintainers prefer is fine by me — the per-source-root fallback here is also what lets formatting continue when `--config` is\n...[truncated]", "pr_title": "Fall back to the default configuration when sources share no project root"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "8d5a2d9f49378d7abe2eb632df1601818de8c24e", "candidate_corpus": {"base_commit": "8d5a2d9f49378d7abe2eb632df1601818de8c24e", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "f65a19b46a356e613d5f8642839f26d47c0dbc8d", "negative_distractors": [], "related_tests": ["tests/test_black.py"], "root_cause_files": ["src/black/__init__.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "61dd661e1f405f1477861956", "metadata": {"confidence": "weak", "created_at": "2026-09-02T02:58:19Z", "evidence": {"implementation_files": ["src/black/__init__.py"], "related_tests": ["tests/test_black.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-10-01T14:47:27Z", "pr": 5383, "pr_url": "https://github.com/psf/black/pull/5383"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/black/__init__.py"], "pr_body": "### Description\n\nCloses #3505.\n\nBlack reindents to 4 spaces but leaves `# fmt: off` regions alone, so its output can end up mixing indent widths. @JelleZijlstra said as much on the issue:\n\n> So the reason this happen is that Black (correctly) reindents the code to use 4-space indents, except within the `# fmt: off` part, because the user asked us not to format it. So the code it tries to output then has a syntax error from the remaining 2-space indents.\n>\n> I still don't think there is a way we can format these cases correctly, but we should give a better error.\n\nThis is the better error, rather than an attempt to format those cases.\n\nThe forced second pass in `format_str()` parses Black's *own* output, but the `InvalidInput` it raised escaped uncaught, so it surfaced against the user's file:\n\n```console\n$ cat reindent.py\nif __name__ == \"__main__\":\n foo = 3\n # fmt: off\n bar = 1\n baz = 2\n # fmt: on\n qux = 4\n\n$ python -c \"import ast; ast.parse(open('reindent.py').read())\" # the file is valid\n\n$ black reindent.py\nerror: cannot parse: reindent.py:5:0\n baz = 2\n ^\nParseError: bad input\n```\n\nThat is byte-for-byte the shape of a genuine syntax error. `def f(:` produces `error: cannot parse: genuine.py:1:6` and the same `ParseError: bad input`, so there is nothing for a user to tell them apart, and it points at a line of their code that is fine.\n\nAfter:\n\n```console\n$ black reindent.py\nerror: cannot format reindent.py: INTERNAL ERROR: Black 0.1.dev20 on Python (CPython) 3.12.13\nproduced invalid code: cannot parse: 5:0\n baz = 2\n ^\nParseError: bad input. Please report a bug on https://github.com/psf/black/issues.\nThis invalid output might be helpful: /tmp/blk_iwhhpmsr.log\n```\n\nThis also restores what @ichard26 described as missing:\n\n> Usually Black wou\n...[truncated]", "pr_title": "Report Black's own parse failure as an internal error"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "8947c48ef2077c3a301b03c1e814dc2e3f78436e", "candidate_corpus": {"base_commit": "8947c48ef2077c3a301b03c1e814dc2e3f78436e", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "7adeae01474047c1de3b5dcfdc3c013457ef44ad", "negative_distractors": [], "related_tests": ["tests/test_ipynb.py"], "root_cause_files": ["src/black/handle_ipynb_magics.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "23601ae22a8f832aa781c334", "metadata": {"confidence": "weak", "created_at": "2026-09-01T14:06:18Z", "evidence": {"implementation_files": ["src/black/handle_ipynb_magics.py"], "related_tests": ["tests/test_ipynb.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-09-03T16:30:59Z", "pr": 5381, "pr_url": "https://github.com/psf/black/pull/5381"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/black/handle_ipynb_magics.py"], "pr_body": "### Description\n\nFixes #5378.\n\n`ast.col_offset` counts UTF-8 bytes, but `replace_magics()` used the value as a Python string index. When non-ASCII characters appeared before an assignment magic, Black kept part of the transformed `get_ipython()` call and produced source that could not be parsed.\n\nBuild the preserved prefix from the UTF-8 bytes before replacing the magic with its mask. The regression test covers a CJK identifier in both the default and custom cell-magic modes.\n\n### Validation\n\n- `tox -e py`\n- `pre-commit run -a`\n- Black self-format check\n\n### Checklist - did you ...\n\n- [x] Implement any code style changes under the `--preview` style, following the stability policy?\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests if necessary?\n- [x] Add new / update outdated documentation?", "pr_title": "Handle UTF-8 offsets when masking notebook magics"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "edd138ee3049749190de3dcd7e32d7bcbf224e41", "candidate_corpus": {"base_commit": "edd138ee3049749190de3dcd7e32d7bcbf224e41", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "f5a53463ad2ff791fc02418b645750ce75a260ad", "negative_distractors": [], "related_tests": ["src/helper/accepts/accepts.test.ts"], "root_cause_files": ["src/helper/accepts/accepts.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "8ab97b7c484815b6daae09d8", "metadata": {"confidence": "weak", "created_at": "2026-09-12T17:27:44Z", "evidence": {"implementation_files": ["src/helper/accepts/accepts.ts"], "related_tests": ["src/helper/accepts/accepts.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-20T08:33:52Z", "pr": 5376, "pr_url": "https://github.com/honojs/hono/pull/5376"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["src/helper/accepts/accepts.ts"], "pr_body": "Fixes #5375.\n\n`matchType()` compared the accept header entry and the supported value as raw strings, so `Accept: TEXT/HTML` did not match a supported `text/html`, and `Accept-Language: en-us` did not match `en-US`.\n\nMedia types are case-insensitive (RFC 9110 §8.3.1) and so are language tags (RFC 4647 §2.1). The subtype wildcard path had the same problem, so `TEXT/*` did not match `text/html` either.\n\n#5064 already made `parseBody()` and `validator()` match media types case-insensitively, for #5060. `accepts()` was not part of that change.\n\n### Change\n\nCompare case-folded inside `matchType()`. `defaultMatch()` returns the caller's own `supports` entry, so the casing an application registered is preserved, and `q=0` entries are still rejected regardless of case.\n\nAdded tests for both headers, the wildcard case, and a case-different `q=0` entry.", "pr_title": "fix(accepts): match media types and language tags case-insensitively"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "b5b1eb6f60ce9febc473c6cb49f935954d108678", "candidate_corpus": {"base_commit": "b5b1eb6f60ce9febc473c6cb49f935954d108678", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "0b50123abb27a59a8aac517a89ac4fec739dae24", "negative_distractors": [], "related_tests": ["tests/data/cases/preview_redundant_generator_parentheses.py"], "root_cause_files": ["src/black/linegen.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "4b0d4aaadc1ec27cebedf5ce", "metadata": {"confidence": "weak", "created_at": "2026-08-30T18:02:08Z", "evidence": {"implementation_files": ["src/black/linegen.py"], "related_tests": ["tests/data/cases/preview_redundant_generator_parentheses.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-09-22T21:08:39Z", "pr": 5369, "pr_url": "https://github.com/psf/black/pull/5369"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/black/linegen.py"], "pr_body": "### Description\n\n`black --preview` refuses to format `outer(inner(((x for x in y))))` when the generator is long enough to split:\n\n```\nerror: cannot format g.py: INTERNAL ERROR: Black produced different code on the second pass of the formatter.\n```\n\n`visit_power` only spots a sole-argument generator when the call's argument is the generator atom itself, so with a second redundant pair it does nothing and `visit_atom` removes just the outer pair. The pair left behind keeps the generator inside a bracket, so the `for` never registers as a delimiter and the line breaks inside the element expression instead. Re-parsing that output drops the surviving pair and splits at the `for`, hence the two passes disagree.\n\n`visit_power` now also accepts a nested redundant-paren atom, and `maybe_make_parens_invisible_in_atom` forwards `remove_generator_parens` into its recursion so the inner pair goes too. The result matches what the one-pair spelling already produced.\n\nPreview only. Formatting 2589 files across three modes gives byte-identical output before and after, and the stable style is untouched.\n\n### Checklist - did you ...\n\n- [x] Implement any code style changes under the `--preview` style, following the stability policy?\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests if necessary?\n- [x] Add new / update outdated documentation? (`future_style.md` already describes the feature; no behavior to add there)", "pr_title": "Format a call whose sole argument is a parenthesized generator under --preview"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "eebdf7be39abf0a872671835ccce0c4f03ea497a", "candidate_corpus": {"base_commit": "eebdf7be39abf0a872671835ccce0c4f03ea497a", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "e7b38ee42bfa41f20194ad20fb949b625346be62", "negative_distractors": ["src/utils/types.ts"], "related_tests": ["src/helper/cookie/index.test.ts"], "root_cause_files": ["src/context.ts", "src/helper/proxy/index.ts", "src/helper/route/index.ts", "src/utils/types.ts"], "root_cause_symbols": [], "supporting_files": ["README.md"]}, "id": "24954e84c5b06a78f0b4f881", "metadata": {"confidence": "weak", "created_at": "2026-09-06T15:15:40Z", "evidence": {"implementation_files": ["src/context.ts", "src/helper/proxy/index.ts", "src/helper/route/index.ts", "src/utils/types.ts"], "related_tests": ["src/helper/cookie/index.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-08T09:59:09Z", "pr": 5343, "pr_url": "https://github.com/honojs/hono/pull/5343"}, "query": {"changed_file_summary": "4 implementation files and 1 existing test files changed within 6 total files.", "implementation_file_count": 4, "implementation_files": ["src/context.ts", "src/helper/proxy/index.ts", "src/helper/route/index.ts", "src/utils/types.ts"], "pr_body": "### The author should do the following, if applicable\n\n- [ ] Add tests\n- [X] Run tests\n- [X] `bun run format:fix && bun run lint:fix` to format the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code", "pr_title": "docs: fix typos in code comments and link third-party middleware section"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "eebdf7be39abf0a872671835ccce0c4f03ea497a", "candidate_corpus": {"base_commit": "eebdf7be39abf0a872671835ccce0c4f03ea497a", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "7792f5dc14acaa92056c1bf402241567ff9c7396", "negative_distractors": [], "related_tests": ["src/jsx/dom/index.test.tsx"], "root_cause_files": ["benchmarks/jsx-dom/benchmark.ts", "src/jsx/dom/render.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "e2a92e82dc78b1ba46eeae0a", "metadata": {"confidence": "weak", "created_at": "2026-09-06T02:17:09Z", "evidence": {"implementation_files": ["benchmarks/jsx-dom/benchmark.ts", "src/jsx/dom/render.ts"], "related_tests": ["src/jsx/dom/index.test.tsx"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-10T00:34:09Z", "pr": 5340, "pr_url": "https://github.com/honojs/hono/pull/5340"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 2, "implementation_files": ["benchmarks/jsx-dom/benchmark.ts", "src/jsx/dom/render.ts"], "pr_body": "fixes #5306.\n\nReduce repeated linear searches during large keyed child updates while preserving existing node reuse, component state, and cleanup order.\n\n- Keep the existing forward `findIndex()` / `splice()` path for inexpensive updates.\n- Try building a key index once accumulated search work exceeds a linear budget.\n- Use the index only when the remaining old children have unique keys, including at most one `undefined` key.\n- Preserve strict key and tag matching, distinguish text nodes from elements, and retain the original removal order.\n- Fall back to array matching for new unkeyed elements so they can still reuse keyed old children with the same tag.\n\n## Scope and relationship to #5329\n\nThis targets expensive searches during large keyed reorders. It does not make all reconciliation linear: in-order array shifts remain, and duplicate-key or unkeyed fallback paths can still require quadratic work. DOM placement is unchanged.\n\nThis branch is based directly on main and does not include #5329. That PR optimizes matching-head updates; this one addresses expensive searches. If #5329 lands first, this branch can be rebased to preserve its fast path alongside the indexed path.\n\n## Benchmark\n\n```sh\nbun benchmarks/jsx-dom/benchmark.ts\n```\n\nThe benchmark measures `build()` only, excluding JSX creation and DOM updates. It covers 100, 1,000, and 5,000 keyed children.\n\nThe same benchmark script was run against main (`eebdf7be`) and this branch (`0130dd16`) using **Bun 1.3.12 on an Apple M5 Pro**. Results below are for **5,000 keyed children**, with one additional unkeyed child in the footer case.\n\n| Update | main (ms/build) | This PR (ms/build) |\n| --- | ---: | ---: |\n| Same order | 1.389 | 1.428 |\n| Remove the second child | 1.564 | 1.586 |\n| Adjacent swap | 1.362 | 1.413 |\n| Re\n...[truncated]", "pr_title": "perf(jsx/dom): reduce lookup work for large keyed updates"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "2b96e280653fd79f593c942191d8614ca6ce39e6", "candidate_corpus": {"base_commit": "2b96e280653fd79f593c942191d8614ca6ce39e6", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "9f9c675f27fa96f2a901fb0cb8ac3b5d8d579c79", "negative_distractors": [], "related_tests": ["tests/data/cases/preview_comments7.py"], "root_cause_files": ["src/black/trans.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "8766ef098d39975d77693f5f", "metadata": {"confidence": "weak", "created_at": "2026-08-20T12:01:39Z", "evidence": {"implementation_files": ["src/black/trans.py"], "related_tests": ["tests/data/cases/preview_comments7.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-09-24T21:21:21Z", "pr": 5329, "pr_url": "https://github.com/psf/black/pull/5329"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/black/trans.py"], "pr_body": "### Description\n\nIn the transformation process of formatting a complicated expression with a `# type: ignore` comment at the end, the comment was getting lost. This was in turn crashing Black on the `--unstable` style.\n\nFix the issue by moving comments from `old_rpar_leaf` to the new last line of the transformed code after a transformation. It seems this was missed in the initial implementation.\n\nThis PR is a direct fix for #5328.\n\n### Checklist - did you ...\n\n- [x] Implement any code style changes under the `--preview` style, following the stability policy?\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests if necessary?\n- [ ] ~Add new / update outdated documentation?~\n\nFIXES: #5328", "pr_title": "Fix a crash when `# type: ignore` is lost during formatting"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "499c35ebda35777fd35a7dd1906dd4f2687da61e", "candidate_corpus": {"base_commit": "499c35ebda35777fd35a7dd1906dd4f2687da61e", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "f147de5ea1eeadd4b4851ab075999673e140a303", "negative_distractors": [], "related_tests": ["src/helper/accepts/accepts.test.ts", "src/middleware/language/index.test.ts"], "root_cause_files": ["src/helper/accepts/accepts.ts", "src/middleware/language/language.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "0a6dbeccc8dc1c6a207b9588", "metadata": {"confidence": "weak", "created_at": "2026-08-28T03:42:22Z", "evidence": {"implementation_files": ["src/helper/accepts/accepts.ts", "src/middleware/language/language.ts"], "related_tests": ["src/helper/accepts/accepts.test.ts", "src/middleware/language/index.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-12T08:36:45Z", "pr": 5311, "pr_url": "https://github.com/honojs/hono/pull/5311"}, "query": {"changed_file_summary": "2 implementation files and 2 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["src/helper/accepts/accepts.ts", "src/middleware/language/language.ts"], "pr_body": "`accepts()` (`defaultMatch`) and the language detector's header detection still match entries with quality `0`, which RFC 9110 §12.5.1/§12.5.4 defines as \"explicitly not acceptable\" — e.g. `Accept: application/json;q=0` was served `application/json`.\n\nThis change:\n\n- `src/helper/accepts/accepts.ts` — `defaultMatch` filters out `q=0` entries before matching\n- `src/middleware/language/language.ts` — `detectFromHeader` skips `q=0` languages\n\nThis aligns both consumers with the rule the `compress` middleware already applies (`q > 0` in `getEncoding`). `parseAccept` / `parseAcceptLanguage` are left unchanged, so custom `match` functions and direct callers still see the full list.\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `bun run format:fix && bun run lint:fix` to format the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code (no public API change)\n\nTests: full suite `vitest --run` → 147 files, 4964 passed; `tsc -p tsconfig.spec.json` clean; new regression tests cover both `accepts()` and `languageDetector`.\n\nFixes #5310", "pr_title": "fix(accepts, language): skip accept entries with quality 0 when matching"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "612b59c0227b421090d46721cd5a98243ad8c6ec", "candidate_corpus": {"base_commit": "612b59c0227b421090d46721cd5a98243ad8c6ec", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "c409d855d91d1f0904d19439692216fcf789e6cb", "negative_distractors": [], "related_tests": ["src/request.test.ts"], "root_cause_files": ["src/request.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "b384a6c070afcf0952ade7c1", "metadata": {"confidence": "weak", "created_at": "2026-08-23T07:14:07Z", "evidence": {"implementation_files": ["src/request.ts"], "related_tests": ["src/request.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-23T07:16:58Z", "pr": 5288, "pr_url": "https://github.com/honojs/hono/pull/5288"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["src/request.ts"], "pr_body": "### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `bun run format:fix && bun run lint:fix` to format the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code", "pr_title": "fix(request): serialize cached JSON body in cloneRawRequest"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "2059584f84187a688354956e0647269834ccf3a6", "candidate_corpus": {"base_commit": "2059584f84187a688354956e0647269834ccf3a6", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "c4a44071eee614c7317403f3534cd213d3f0e0b3", "negative_distractors": [], "related_tests": ["src/client/client.test.ts"], "root_cause_files": ["src/client/client.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "407bb2770bf2852fdf7c0819", "metadata": {"confidence": "weak", "created_at": "2026-08-22T05:30:36Z", "evidence": {"implementation_files": ["src/client/client.ts"], "related_tests": ["src/client/client.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-22T05:32:47Z", "pr": 5280, "pr_url": "https://github.com/honojs/hono/pull/5280"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["src/client/client.ts"], "pr_body": "### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `bun run format:fix && bun run lint:fix` to format the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code", "pr_title": "fix(client): skip an undefined entry inside a form array"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "4b44abe1b5c7755aac8555d7943611555183450b", "candidate_corpus": {"base_commit": "4b44abe1b5c7755aac8555d7943611555183450b", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "5e5b83d6ed963a2bc7d8384002e1c953648253b1", "negative_distractors": [], "related_tests": ["src/utils/stream.test.ts"], "root_cause_files": ["src/utils/stream.ts"], "root_cause_symbols": [], "supporting_files": []}, "id": "a2ce28d3cd629907008cedcc", "metadata": {"confidence": "weak", "created_at": "2026-08-21T11:28:20Z", "evidence": {"implementation_files": ["src/utils/stream.ts"], "related_tests": ["src/utils/stream.test.ts"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-23T07:34:05Z", "pr": 5274, "pr_url": "https://github.com/honojs/hono/pull/5274"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["src/utils/stream.ts"], "pr_body": "`StreamingApi.abort()` invokes every abort subscriber bare:\n\n```ts\nthis.abortSubscribers.forEach((subscriber) => subscriber())\n```\n\n`onAbort` accepts `() => void | Promise`, and the first built-in subscriber is async (`await reader.cancel()`), so two failure modes exist on the client-disconnect path that triggers `abort()`:\n\n- an async listener that rejects (cleanup RPC fails, resource already gone) becomes an unhandled promise rejection, which crashes the process under Node's default policy;\n- a listener that throws synchronously stops the `forEach`, so the remaining listeners never run, including the built-in reader cancel when user listeners were registered before it runs.\n\nThe fix contains errors per listener: sync throws are caught, and a returned promise gets a no-op catch. Silently containing them matches the policy `write()` in the same class already applies (\"Do nothing. If you want to handle errors, create a stream by yourself.\").\n\nTwo tests added next to the existing `abort()` specs:\n\n- a throwing listener must not prevent later listeners from running;\n- a rejecting async listener must not produce an unhandled rejection (asserted via a `process.on('unhandledRejection')` capture).\n\nVerification with the repo's vitest setup: with the fix, 13 passed (13); with current main's `stream.ts` and only the tests added, 2 failed | 11 passed, the two failures being exactly the new cases.\n\nThe author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `bun run format:fix && bun run lint:fix` to format the code\n- [ ] Add [docs](https://github.com/honojs/website)", "pr_title": "fix(utils/stream): do not let abort listeners crash abort()"}, "query_provenance": "pr_summary", "repo": "honojs/hono", "task_type": "code2test", "version": 2} +{"base_commit": "8140f6e47ed15762ec0bf0d03ee03869fa655ce2", "candidate_corpus": {"base_commit": "8140f6e47ed15762ec0bf0d03ee03869fa655ce2", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "106b148d1dd5bbed90c4fe2fd02fbd7ad380b5dd", "negative_distractors": [], "related_tests": ["tests/data/cases/preview_wrap_comprehension_in.py"], "root_cause_files": ["src/black/linegen.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "34279bdf18c1677f880c37b8", "metadata": {"confidence": "weak", "created_at": "2026-06-26T07:03:02Z", "evidence": {"implementation_files": ["src/black/linegen.py"], "related_tests": ["tests/data/cases/preview_wrap_comprehension_in.py"], "signals": ["same_pr_changed_implementation_and_tests", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-07-21T00:51:09Z", "pr": 5200, "pr_url": "https://github.com/psf/black/pull/5200"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/black/linegen.py"], "pr_body": "While poking at `wrap_comprehension_in` after #5176, I hit a case it doesn't cover. #5176 keeps the parens around a lambda or ternary used as a comprehension's iterable so the trailing `for`/`if` clauses aren't absorbed into it. But when those parens are redundantly nested, e.g.\n\n```python\n[x for x in ((lambda: 0))]\n```\n\n`maybe_make_parens_invisible_in_atom` recurses and strips *both* pairs, leaving `[x for x in lambda: 0]` — invalid code, which crashes with an `ASTSafetyError` at the default line length. Same for a nested ternary and for generator/dict/set comprehensions, and at deeper nesting.\n\nThe guard only inspected the atom's direct child, so a paren-wrapped atom slipped past it. I made it look through the redundant nested parens before deciding whether the iterable is a lambda/ternary, so at least one pair is kept (matching what the stable style does with such input).\n\nAdded the nested lambda/ternary cases to the existing `preview_wrap_comprehension_in` fixture — they crashed before and pass now. The full test suite, mypy, flake8 and the self-format check are green.", "pr_title": "Keep nested parens around lambda/ternary comprehension iterables (preview)"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "6325332f05312ebde112a61cf4a19ef2ecf1ea74", "candidate_corpus": {"base_commit": "6325332f05312ebde112a61cf4a19ef2ecf1ea74", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "f50ab10f393ac9b22b14c7cbfd60acf0d173c754", "negative_distractors": [], "related_tests": ["tests/data/cases/preview_wrap_comprehension_in.py"], "root_cause_files": ["src/black/linegen.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "fe0339c48b1a2ac8397b84ca", "metadata": {"confidence": "weak", "created_at": "2026-06-12T08:00:36Z", "evidence": {"implementation_files": ["src/black/linegen.py"], "related_tests": ["tests/data/cases/preview_wrap_comprehension_in.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-06-15T18:43:00Z", "pr": 5176, "pr_url": "https://github.com/psf/black/pull/5176"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/black/linegen.py"], "pr_body": "### Description\n\nOn `--preview`, this code crashes Black with an `ASTSafetyError`:\n\n```python\n[x for x in (lambda: 0) if x]\n```\n\n`wrap_comprehension_in` makes the parens around a comprehension's iterable\ninvisible when the inner expression is low-precedence. There's already a guard\nthat keeps them for ternaries, but it only checks for `syms.test`, so a lambda\niterable slips through. Dropping the parens lets the trailing `if`/`for` clauses\nget parsed as part of the lambda body (`lambda: 0 if x`), which isn't valid, so\nBlack emits unparsable output and bails out with an internal error. A bare\n`[x for x in (lambda y: y)]` is broken the same way.\n\nThe fix extends the existing guard to also cover `syms.lambdef`. Long lambda\niterables still get wrapped, just with the parens kept. Hit a few comprehension\nshapes (list/set/dict/genexpr, trailing `if` and `for`) while checking it.\n\n### Checklist - did you ...\n\n- [x] Implement any code style changes under the `--preview` style, following the stability policy?\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests if necessary?\n- [ ] Add new / update outdated documentation?", "pr_title": "Keep parens around lambda iterables in comprehensions (preview)"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "20622e1259c29bda81831962ace1348ba1921c84", "candidate_corpus": {"base_commit": "20622e1259c29bda81831962ace1348ba1921c84", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "d2291c38704220a2adf531e055514c5190200fed", "negative_distractors": ["src/black/lines.py", "src/black/ranges.py", "src/blib2to3/pytree.py"], "related_tests": ["tests/test_black.py"], "root_cause_files": ["src/black/__init__.py", "src/black/comments.py", "src/black/linegen.py", "src/black/lines.py", "src/black/ranges.py", "src/blib2to3/pytree.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md", "tests/data/cases/line_ranges_format_selected_prefix_comment.py", "tests/data/cases/line_ranges_preserve_outside_prefix.py"]}, "id": "de4451b135afc5f5022663bc", "metadata": {"confidence": "weak", "created_at": "2026-06-12T03:49:32Z", "evidence": {"implementation_files": ["src/black/__init__.py", "src/black/comments.py", "src/black/linegen.py", "src/black/lines.py", "src/black/ranges.py", "src/blib2to3/pytree.py"], "related_tests": ["tests/test_black.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-09-21T16:53:07Z", "pr": 5175, "pr_url": "https://github.com/psf/black/pull/5175"}, "query": {"changed_file_summary": "6 implementation files and 1 existing test files changed within 10 total files.", "implementation_file_count": 6, "implementation_files": ["src/black/__init__.py", "src/black/comments.py", "src/black/linegen.py", "src/black/lines.py", "src/black/ranges.py", "src/blib2to3/pytree.py"], "pr_body": "### Description\n\nPreserves comments and blank lines that are outside the requested `--line-ranges` instead of normalizing them while unchanged code is converted to standalone-comment leaves for range formatting.\n\nThis keeps the issue repro constrained to the requested lines: comments and separation before unchanged statements are preserved when the selected range ends immediately before them.\n\nFixes #4430.\n\n### Checklist - did you ...\n\n- [x] Implement any code style changes under the `--preview` style, following the stability policy?\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests if necessary?\n- [x] Add new / update outdated documentation?\n\n### Verification\n\n- `python -m black --check src/black/comments.py src/black/linegen.py src/black/lines.py src/black/ranges.py tests/test_ranges.py`\n- `python -m pytest tests/test_ranges.py tests/test_format.py -q`\n- `git diff --check`", "pr_title": "Preserve prefixes outside --line-ranges"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "ce1897a8f20d0f64844dd666d07f4003500d0e09", "candidate_corpus": {"base_commit": "ce1897a8f20d0f64844dd666d07f4003500d0e09", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "6c136f979c14956eeddb4a20c3f2653bce7e9505", "negative_distractors": [], "related_tests": ["tests/test_black.py"], "root_cause_files": ["src/black/__init__.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "5e03b118b94f6b80a170dd32", "metadata": {"confidence": "weak", "created_at": "2026-06-03T23:42:45Z", "evidence": {"implementation_files": ["src/black/__init__.py"], "related_tests": ["tests/test_black.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-06-08T01:35:19Z", "pr": 5167, "pr_url": "https://github.com/psf/black/pull/5167"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/black/__init__.py"], "pr_body": "### Description\n\nThe `_target_versions_exceed_runtime` function was using `max()` to compare\ntarget versions against the runtime version. This caused a spurious warning\nwhen users specified the runtime version alongside higher target versions\n(e.g., `--target-version py314 --target-version py315` on Python 3.14).\n\nThe fix uses `min()` instead: the warning now only fires when **all** target\nversions exceed the runtime. If any target version is at or below the runtime,\nthe AST safety check can succeed for that version, making the warning\nunnecessary.\n\nCloses #5164.\nCloses #5168.\n\n### Approach\n\n- Changed `max()` to `min()` in `_target_versions_exceed_runtime`\n- Added regression test that verifies no warning when runtime version is\n included in the target set\n- Updated the docstring to clarify the semantics\n\n### AI assistance disclosure\n\nThis contribution was developed with the assistance of an AI coding agent\n(Buck/OpenClaw). All code was reviewed and verified by a human contributor\nbefore submission.\n\n### Checklist - did you ...\n\n- [ ] Implement any code style changes under the `--preview` style, following the stability policy?\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests if necessary?\n- [ ] Add new / update outdated documentation?", "pr_title": "fix: no spurious target-version warning when runtime version is included"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "9cbd95f80e97c1ab4d690d1d41b81579a13bf75c", "candidate_corpus": {"base_commit": "9cbd95f80e97c1ab4d690d1d41b81579a13bf75c", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "ebe6018e3254629788376e619207719fbe34a849", "negative_distractors": [], "related_tests": ["tests/test_black.py"], "root_cause_files": ["src/black/__init__.py"], "root_cause_symbols": [], "supporting_files": [".github/workflows/publish_binaries.yml"]}, "id": "9bb8b9a6690537ddf0ceb85c", "metadata": {"confidence": "weak", "created_at": "2026-05-18T01:07:25Z", "evidence": {"implementation_files": ["src/black/__init__.py"], "related_tests": ["tests/test_black.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-05-18T02:02:11Z", "pr": 5136, "pr_url": "https://github.com/psf/black/pull/5136"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/black/__init__.py"], "pr_body": "### Description\n\n\n\nFixes failing tests caused by Click update (https://github.com/pallets/click/pull/2805)\nAlso resolves Zizmor warning\n\n### Checklist - did you ...\n\n\n\n- [-] Implement any code style changes under the `--preview` style, following the stability policy?\n- [-] Add an entry in `CHANGES.md` if necessary?\n- [y] Add / update tests if necessary?\n- [-] Add new / update outdated documentation?", "pr_title": "CI Hotfixes"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "e079b7e100d1e181d4ee860ee4512bf3326f32c3", "candidate_corpus": {"base_commit": "e079b7e100d1e181d4ee860ee4512bf3326f32c3", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "9fd9ea2835973981e3f5dc5b8eb76f2ded46aa61", "negative_distractors": [], "related_tests": ["tests/test_black.py"], "root_cause_files": ["src/black/__init__.py", "src/black/parsing.py", "src/blackd/__init__.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md"]}, "id": "bd17b96d06a5a071eab17e10", "metadata": {"confidence": "weak", "created_at": "2026-04-06T03:00:29Z", "evidence": {"implementation_files": ["src/black/__init__.py", "src/black/parsing.py", "src/blackd/__init__.py"], "related_tests": ["tests/test_black.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-04-27T14:35:59Z", "pr": 5080, "pr_url": "https://github.com/psf/black/pull/5080"}, "query": {"changed_file_summary": "3 implementation files and 1 existing test files changed within 5 total files.", "implementation_file_count": 3, "implementation_files": ["src/black/__init__.py", "src/black/parsing.py", "src/blackd/__init__.py"], "pr_body": "## Summary\n\nPer @JelleZijlstra's review feedback on #5074, this PR splits the error handling instead of treating all ASTSafetyError as 400.\n\n### Changes\n\n1. **New exception: `SourceASTParseError`** (`src/black/parsing.py`)\n - Raised when the source file cannot be parsed by `ast.parse()` but was accepted by Black's more lenient lib2to3 parser\n - This is a user input issue, not a Black bug\n\n2. **Updated `assert_equivalent`** (`src/black/__init__.py`)\n - Source AST parse failure → `SourceASTParseError` (user input issue)\n - Dest AST parse failure → `ASTSafetyError` (Black bug → 500)\n - Non-equivalent output → `ASTSafetyError` (Black bug → 500)\n\n3. **Updated blackd** (`src/blackd/__init__.py`)\n - `SourceASTParseError` → 400 Bad Request\n - `ASTSafetyError` → 500 Internal Server Error (unchanged, caught by generic Exception handler)\n\n### Closes\nFixes #3616\n\n### Analysis of all ASTSafetyError uses\n| Location | Cause | Error type | blackd status |\n|----------|-------|-----------|---------------|\n| `assert_equivalent` src AST parse fail | User input (lenient parser) | `SourceASTParseError` | 400 |\n| `assert_equivalent` dest AST parse fail | Black bug | `ASTSafetyError` | 500 |\n| `assert_equivalent` src ≠ dst | Black bug | `ASTSafetyError` | 500 |\n| `check_stability_and_equivalence` re-raise | Depends on underlying | Propagated | 400 or 500 |", "pr_title": "Fix blackd error handling: split SourceASTParseError from ASTSafetyError"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "9e969ddc31863a5c353b3f4e8f69d2aca05e36ae", "candidate_corpus": {"base_commit": "9e969ddc31863a5c353b3f4e8f69d2aca05e36ae", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "c7fc2438cbd8ef66f2b9899e6b5094a8c89af63c", "negative_distractors": [], "related_tests": ["tests/test_black.py", "tests/test_format.py"], "root_cause_files": ["src/black/parsing.py"], "root_cause_symbols": [], "supporting_files": ["CHANGES.md", "docs/usage_and_configuration/the_basics.md"]}, "id": "b9518605ee3ce79dadaf85ff", "metadata": {"confidence": "weak", "created_at": "2026-03-29T15:53:47Z", "evidence": {"implementation_files": ["src/black/parsing.py"], "related_tests": ["tests/test_black.py", "tests/test_format.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-04-14T14:44:45Z", "pr": 5068, "pr_url": "https://github.com/psf/black/pull/5068"}, "query": {"changed_file_summary": "1 implementation files and 2 existing test files changed within 5 total files.", "implementation_file_count": 1, "implementation_files": ["src/black/parsing.py"], "pr_body": "Closes #4820\nCloses #4992\n\nI updated the parse error message while still keeping it in readable format.\nNew Change: Now it shows the error in multiple lines , points to the error position with ^.", "pr_title": "Improve parse error readability"}, "query_provenance": "pr_summary", "repo": "psf/black", "task_type": "code2test", "version": 2} +{"base_commit": "19c67b9a3479841e9133bea94607c89ee931d3fc", "candidate_corpus": {"base_commit": "19c67b9a3479841e9133bea94607c89ee931d3fc", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "ffe2edc5968eac19d5493c2d7b27965031a692e9", "negative_distractors": [], "related_tests": ["tests/test_markdown.py"], "root_cause_files": ["rich/markdown.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "ae2c2639cd427d7193f30e15", "metadata": {"confidence": "weak", "created_at": "2026-04-12T07:40:33Z", "evidence": {"implementation_files": ["rich/markdown.py"], "related_tests": ["tests/test_markdown.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-04-12T07:45:03Z", "pr": 4079, "pr_url": "https://github.com/Textualize/rich/pull/4079"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["rich/markdown.py"], "pr_body": "Fixes https://github.com/Textualize/rich/issues/4038", "pr_title": "Inline table code"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "58ac15120fe254886c10d6253667733c83604cb4", "candidate_corpus": {"base_commit": "58ac15120fe254886c10d6253667733c83604cb4", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "19c67b9a3479841e9133bea94607c89ee931d3fc", "negative_distractors": [], "related_tests": ["tests/test_file_proxy.py"], "root_cause_files": ["rich/file_proxy.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "00cecdb54c59c8503a5ca31a", "metadata": {"confidence": "weak", "created_at": "2026-04-12T04:06:31Z", "evidence": {"implementation_files": ["rich/file_proxy.py"], "related_tests": ["tests/test_file_proxy.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-04-12T04:11:19Z", "pr": 4077, "pr_url": "https://github.com/Textualize/rich/pull/4077"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["rich/file_proxy.py"], "pr_body": "Fixes https://github.com/Textualize/rich/issues/4041", "pr_title": "proxy isatty"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "9cb198944f8184df92217efc8b20d3fffa4b4fa0", "candidate_corpus": {"base_commit": "9cb198944f8184df92217efc8b20d3fffa4b4fa0", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "58ac15120fe254886c10d6253667733c83604cb4", "negative_distractors": [], "related_tests": ["tests/test_ansi.py"], "root_cause_files": ["rich/ansi.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "docs/source/console.rst"]}, "id": "2522ca7eff5310e632b540e5", "metadata": {"confidence": "weak", "created_at": "2026-04-11T10:33:23Z", "evidence": {"implementation_files": ["rich/ansi.py"], "related_tests": ["tests/test_ansi.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-04-12T03:59:42Z", "pr": 4076, "pr_url": "https://github.com/Textualize/rich/pull/4076"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 1, "implementation_files": ["rich/ansi.py"], "pr_body": "Fixes https://github.com/Textualize/rich/issues/3577", "pr_title": "preserve newlines"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "fc41075a3206d2a5fd846c6f41c4d2becab814fa", "candidate_corpus": {"base_commit": "fc41075a3206d2a5fd846c6f41c4d2becab814fa", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "7f40063da781f4990d21423f23f7ccb3165ce0bd", "negative_distractors": ["rich/logging.py", "rich/protocol.py", "rich/repr.py", "rich/segment.py", "rich/syntax.py", "rich/theme.py"], "related_tests": ["tests/test_console.py", "tests/test_syntax.py"], "root_cause_files": ["rich/_emoji_replace.py", "rich/console.py", "rich/emoji.py", "rich/logging.py", "rich/protocol.py", "rich/repr.py", "rich/segment.py", "rich/syntax.py"], "root_cause_symbols": [], "supporting_files": ["rich/theme.py", "CHANGELOG.md", "CONTRIBUTORS.md"]}, "id": "70b8fc7fc66d606cf7608817", "metadata": {"confidence": "weak", "created_at": "2026-04-09T04:39:42Z", "evidence": {"implementation_files": ["rich/_emoji_replace.py", "rich/console.py", "rich/emoji.py", "rich/logging.py", "rich/protocol.py", "rich/repr.py", "rich/segment.py", "rich/syntax.py", "rich/theme.py"], "related_tests": ["tests/test_console.py", "tests/test_syntax.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-04-11T02:38:58Z", "pr": 4070, "pr_url": "https://github.com/Textualize/rich/pull/4070"}, "query": {"changed_file_summary": "9 implementation files and 2 existing test files changed within 13 total files.", "implementation_file_count": 9, "implementation_files": ["rich/_emoji_replace.py", "rich/console.py", "rich/emoji.py", "rich/logging.py", "rich/protocol.py", "rich/repr.py", "rich/segment.py", "rich/syntax.py"], "pr_body": "## E2E Results\n\n| Import | master | This PR | Speedup |\n|---|---|---|---|\n| `from rich.console import Console` | 78.1ms | 52.2ms | **1.50x faster** |\n| `from rich.logging import RichHandler` | 99.4ms | 56.9ms | **1.75x faster** |\n| `import rich` | 18.2ms | 18.3ms | (already lean) |\n\n## Summary\n\nDefer module-level imports that are only needed in specific code paths, move annotation-only imports to `TYPE_CHECKING`, and remove dead code:\n\n| File | Change | Savings |\n|---|---|---|\n| `logging.py` | Defer `Traceback` to `emit()` (only when `rich_tracebacks=True`) | ~20ms |\n| `logging.py` | `from __future__ import annotations` + `TYPE_CHECKING` for `Console`, `ConsoleRenderable`, `Highlighter`, `FormatTimeCallable` | ~6ms |\n| `logging.py` | Replace `pathlib.Path` → `os.path.basename` (also a minor runtime win) | ~4-5ms |\n| `console.py` | Eliminate `import inspect`; replace `isclass` → `isinstance(x, type)`, `currentframe` → `sys._getframe` | ~10ms |\n| `console.py` | Defer `pretty` to `Console.print()` | ~3-5ms |\n| `console.py` | Defer `scope` to `Console.log()` (only when `log_locals=True`) | ~3-5ms |\n| `console.py` | Defer `getpass` to `Console.input()` (only when `password=True`) | ~2ms |\n| `console.py` | Defer `html.escape` and `zlib` to export methods | ~2.3ms |\n| `console.py` | Remove dead `_svg_hash` function (unused since 113997ac, fixes latent NameError) | cleanup |\n| `segment.py` | Remove dead `logging` import (`getLogger` assigned but never used) | ~2-3ms |\n| `theme.py` | Defer `configparser` to `Theme.from_file()` | ~1.5ms |\n| `syntax.py` | Move `Console`, `ConsoleOptions`, `JustifyMethod`, `RenderResult` to `TYPE_CHECKING` | eliminates console.py from syntax import chain |\n| `protocol.py` | Replace `from inspect import isclass` → `isinstance(x, type)` | prepares fo\n...[truncated]", "pr_title": "perf: reduce Console and RichHandler import time by deferring unused imports"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "7323a7514f7601737640e7172be115127d6db08c", "candidate_corpus": {"base_commit": "7323a7514f7601737640e7172be115127d6db08c", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "4987f76709aae3a1c4db723c53874c9ddcb0c4fd", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/vscreen.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "70b3da938579fcf669b5f2d0", "metadata": {"confidence": "weak", "created_at": "2026-09-22T11:56:08Z", "evidence": {"implementation_files": ["src/vscreen.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-09-22T18:13:31Z", "pr": 4015, "pr_url": "https://github.com/sharkdp/bat/pull/4015"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/vscreen.rs"], "pr_body": "## Summary\n\n`src/vscreen.rs` tracks the terminal's active ANSI style in an `Attributes` struct so bat can re-apply it before each syntax-highlighted token (nu_ansi_term appends a full `\\x1B[0m` reset after every token). The struct already has a `strike` field, documented `ON: ^[9m / OFF: ^[29m`, that is initialized, cleared in `sgr_reset()`, and re-emitted in `Display` — but `update_with_sgr()` had **no match arm for SGR `9` or `29`**, so `strike` was only ever cleared, never set.\n\nConsequence: with ANSI passthrough (the default — `--strip-ansi` and `--sanitize` both default to `never`), bold/dim/italic/underline survive across highlighted tokens because they are tracked and re-emitted, but strikethrough visibly disappears after the first token.\n\nThis adds the missing `9` (set) and `29` (clear) arms, mirroring the sibling underline (`4`/`24`) and italic (`3`/`23`) arms, so strikethrough persists like every other supported attribute. Two-line behavioral change; no API change. `to_reset_sequence()` intentionally does not reset SGR attributes yet (existing commented-out TODO), so `strike` is handled there exactly like bold/italic — no change needed.\n\n## Test Plan\n\n- `cargo test` (unit + integration).\n- Extended the `test_sgr_attributes_do_not_leak_into_wrong_field` unit test to include SGR `9`, and added `test_sgr_strike_is_tracked_and_cleared` covering set (`9`) and clear (`29`).\n- Added integration test `ansi_sgr_strike_joins_attributes_when_wrapped`, modeled on the existing `ansi_sgr_joins_attributes_when_wrapped`, asserting strikethrough is re-emitted across a wrap boundary. It fails before the fix and passes after.\n\nDeveloped with assistance from Claude Code; reviewed & validated by me.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)", "pr_title": "Track strikethrough (SGR 9) so it is not dropped across highlighted tokens"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "27701029082052c6541031b6f139097230253900", "candidate_corpus": {"base_commit": "27701029082052c6541031b6f139097230253900", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "7338cb9dafd0d0e916585f191ae505b3e602bb51", "negative_distractors": [], "related_tests": ["tests/test_cells.py"], "root_cause_files": ["rich/cells.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "25c2add52318143271387b89", "metadata": {"confidence": "weak", "created_at": "2026-02-19T14:02:49Z", "evidence": {"implementation_files": ["rich/cells.py"], "related_tests": ["tests/test_cells.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-02-19T17:04:17Z", "pr": 4006, "pr_url": "https://github.com/Textualize/rich/pull/4006"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["rich/cells.py"], "pr_body": "Fix for https://github.com/Textualize/rich/issues/3958", "pr_title": "fix for infinite loop in split_graphemes"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "1d402e0c59f8765e420a5a4440eb2fca7465d1ae", "candidate_corpus": {"base_commit": "1d402e0c59f8765e420a5a4440eb2fca7465d1ae", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "0752ff047295131d98f24284e1d949300cd6f4c1", "negative_distractors": [], "related_tests": ["tests/test_cells.py"], "root_cause_files": ["rich/cells.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "pyproject.toml"]}, "id": "6b9b04bf452cbe323ee3055c", "metadata": {"confidence": "weak", "created_at": "2026-02-01T15:01:14Z", "evidence": {"implementation_files": ["rich/cells.py"], "related_tests": ["tests/test_cells.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-02-01T16:19:21Z", "pr": 3953, "pr_url": "https://github.com/Textualize/rich/pull/3953"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 1, "implementation_files": ["rich/cells.py"], "pr_body": "Fixes https://github.com/Textualize/rich/issues/3947\nFixes https://github.com/Textualize/rich/issues/3950", "pr_title": "Fix ZWJ and edge cases"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "36fe3f7ca9becca4777861d5e6e625f5a4a37545", "candidate_corpus": {"base_commit": "36fe3f7ca9becca4777861d5e6e625f5a4a37545", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "f2a1c3b8a8f7edc41b1954cc3fb66bae32293a5e", "negative_distractors": [], "related_tests": ["tests/test_cells.py"], "root_cause_files": ["rich/cells.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "pyproject.toml"]}, "id": "05f404b342048e15e0b86e18", "metadata": {"confidence": "weak", "created_at": "2026-01-24T21:33:50Z", "evidence": {"implementation_files": ["rich/cells.py"], "related_tests": ["tests/test_cells.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-01-24T21:40:01Z", "pr": 3944, "pr_url": "https://github.com/Textualize/rich/pull/3944"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 1, "implementation_files": ["rich/cells.py"], "pr_body": "Fixes https://github.com/Textualize/rich/issues/3943", "pr_title": "fix fonts"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "05ff970926cbd0b5d0acb6fc18cdbd1fc971e582", "candidate_corpus": {"base_commit": "05ff970926cbd0b5d0acb6fc18cdbd1fc971e582", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "3286095ff8b70e093dbbc4136ff7ba7d51944bec", "negative_distractors": [], "related_tests": ["tests/test_segment.py", "tests/test_text.py"], "root_cause_files": ["rich/console.py", "rich/segment.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "24a20206dc0ec5157a7ab098", "metadata": {"confidence": "weak", "created_at": "2026-01-23T15:04:54Z", "evidence": {"implementation_files": ["rich/console.py", "rich/segment.py"], "related_tests": ["tests/test_segment.py", "tests/test_text.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-01-23T15:33:08Z", "pr": 3938, "pr_url": "https://github.com/Textualize/rich/pull/3938"}, "query": {"changed_file_summary": "2 implementation files and 2 existing test files changed within 5 total files.", "implementation_file_count": 2, "implementation_files": ["rich/console.py", "rich/segment.py"], "pr_body": "Fixes https://github.com/Textualize/rich/issues/3838", "pr_title": "fix background style with soft wrap"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "05a6b9b17a7c778756187f15d6d4bf693db6345f", "candidate_corpus": {"base_commit": "05a6b9b17a7c778756187f15d6d4bf693db6345f", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "05ff970926cbd0b5d0acb6fc18cdbd1fc971e582", "negative_distractors": [], "related_tests": ["tests/test_text.py"], "root_cause_files": ["rich/text.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "c9e253deb4c7d5864561e122", "metadata": {"confidence": "weak", "created_at": "2026-01-23T13:31:25Z", "evidence": {"implementation_files": ["rich/text.py"], "related_tests": ["tests/test_text.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-01-23T13:44:59Z", "pr": 3937, "pr_url": "https://github.com/Textualize/rich/pull/3937"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["rich/text.py"], "pr_body": "Fixes https://github.com/Textualize/rich/issues/3841", "pr_title": "don't strip whitespace when soft_wrap is True"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "fe55a131c2780fa856464ad04d7d6dc8a1079b72", "candidate_corpus": {"base_commit": "fe55a131c2780fa856464ad04d7d6dc8a1079b72", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "9e18b96652f37293121b04017fb6aa95af21b013", "negative_distractors": [], "related_tests": ["tests/test_columns.py", "tests/test_table.py"], "root_cause_files": ["rich/table.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "59da79c08c22346cb854feec", "metadata": {"confidence": "weak", "created_at": "2026-01-23T11:21:22Z", "evidence": {"implementation_files": ["rich/table.py"], "related_tests": ["tests/test_columns.py", "tests/test_table.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-01-23T11:31:32Z", "pr": 3935, "pr_url": "https://github.com/Textualize/rich/pull/3935"}, "query": {"changed_file_summary": "1 implementation files and 2 existing test files changed within 4 total files.", "implementation_file_count": 1, "implementation_files": ["rich/table.py"], "pr_body": "Fixes https://github.com/Textualize/rich/issues/3871", "pr_title": "fix for padding width"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "6764b24739b580c0c32ff5ef0b971ed4cfcf4f75", "candidate_corpus": {"base_commit": "6764b24739b580c0c32ff5ef0b971ed4cfcf4f75", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "e9a5680682e0dbaf9e0f3f0fc2a771612307bc3d", "negative_distractors": [], "related_tests": ["tests/test_live.py"], "root_cause_files": ["rich/live.py", "rich/live_render.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "ee6e0046a0df0d5591bc8a12", "metadata": {"confidence": "weak", "created_at": "2026-01-22T16:56:20Z", "evidence": {"implementation_files": ["rich/live.py", "rich/live_render.py"], "related_tests": ["tests/test_live.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-01-22T17:03:12Z", "pr": 3934, "pr_url": "https://github.com/Textualize/rich/pull/3934"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["rich/live.py", "rich/live_render.py"], "pr_body": "Fixes https://github.com/Textualize/rich/issues/3796", "pr_title": "empty live"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "16b5f99d16773ba87cd1a2e40976a2cd3648b75f", "candidate_corpus": {"base_commit": "16b5f99d16773ba87cd1a2e40976a2cd3648b75f", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "7323a7514f7601737640e7172be115127d6db08c", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/bin/bat/clap_app.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "tests/examples/bat-show-all.conf"]}, "id": "526eec567059c69d44234ec7", "metadata": {"confidence": "weak", "created_at": "2026-09-04T10:01:56Z", "evidence": {"implementation_files": ["src/bin/bat/clap_app.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-09-04T19:10:30Z", "pr": 3912, "pr_url": "https://github.com/sharkdp/bat/pull/3912"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 1, "implementation_files": ["src/bin/bat/clap_app.rs"], "pr_body": "bat prepends the arguments from its config file to the command line. So a user who keeps `--show-all` in `~/.config/bat/config` and then types `bat -A file` passes the flag twice, and clap rejects it:\n\n```console\n$ printf -- '--show-all\\n' > ~/.config/bat/config\n$ bat -A src/main.rs\nerror: the argument '--show-all' cannot be used multiple times\n$ echo $?\n2\n```\n\nThe file is never displayed. `--plain` and `--number` do not have this problem, because they already override themselves; `--show-all` and seven others do not.\n\nMeasured on `master` and this branch, once through the config file and once by passing the flag twice directly:\n\n| flag | master: config + CLI | master: CLI twice | this branch |\n|---|---|---|---|\n| `--show-all` | error | error | ok |\n| `--diff` | error | error | ok |\n| `--chop-long-lines` | error | error | ok |\n| `--squeeze-blank` | error | error | ok |\n| `--unbuffered` | error | error | ok |\n| `--quiet-empty` | error | error | ok |\n| `--no-custom-assets` | error | error | ok |\n| `--set-terminal-title` | error | error | ok |\n\nThe fix is `.overrides_with(\"\")`, which is what `plain`, `number`, `number-nonblank`, `force-colorization` and `no-paging` already do.\n\nTwo things I checked rather than assumed, since `overrides_with` on a `SetTrue` flag could plausibly make the second occurrence turn the first one off, or interfere with the existing conflict rules:\n\n- Giving a flag twice produces **byte-identical output** to giving it once, for `-A`, `-s`, `-d` and `--chop-long-lines`. The flag still takes effect.\n- `-A -l rust` still exits 2, so `--show-all`'s `conflicts_with(\"language\")` is unaffected.\n\nSingle-use output is byte-identical to `master` for every flag touched.\n\nThe two added tests fail on `master` — I checked by reverting only the `clap_app.rs\n...[truncated]", "pr_title": "Allow boolean flags to be repeated"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "83366c2b275599366d0b914b27128141cf4ca936", "candidate_corpus": {"base_commit": "83366c2b275599366d0b914b27128141cf4ca936", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "f8b02f22cf10bee707bda19b58265b9e33677535", "negative_distractors": [], "related_tests": ["axum/src/routing/tests/merge.rs"], "root_cause_files": ["axum/src/routing/path_router.rs"], "root_cause_symbols": [], "supporting_files": ["axum/CHANGELOG.md"]}, "id": "2106229e2c33ed333d88c724", "metadata": {"confidence": "weak", "created_at": "2026-09-29T14:36:30Z", "evidence": {"implementation_files": ["axum/src/routing/path_router.rs"], "related_tests": ["axum/src/routing/tests/merge.rs"], "signals": ["same_pr_changed_implementation_and_tests", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-09-30T06:02:38Z", "pr": 3909, "pr_url": "https://github.com/tokio-rs/axum/pull/3909"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["axum/src/routing/path_router.rs"], "pr_body": "## Motivation\n\n`PathRouter::merge` hands each of the other router's endpoints back to `route` or `route_service`. For `Endpoint::Route`, the endpoint is already a `Route`, but `route_service` wraps it in `Route::new` again. Each merge of a router that holds a service route (`route_service`, `nest_service` and so on) therefore adds another layer of boxing and a `RouteFuture`. Every request to that route then pays for an extra clone of the service and an extra dynamic dispatch.\n\n## Solution\n\nInsert the existing `Route` with `route_endpoint` instead of calling `route_service`. Nothing else changes: the path is still validated and conflicts are still reported the same way.\n\nThe new test counts how many times a service is cloned while it handles a request, and checks that a merged service route is cloned as often as the same route used directly. Before this change it was cloned twice per request instead of once.", "pr_title": "axum: Don't wrap merged service routes in another Route"}, "query_provenance": "pr_summary", "repo": "tokio-rs/axum", "task_type": "code2test", "version": 2} +{"base_commit": "2ed8b010afb59c8b8463ad6818c4ee50fa1f17ee", "candidate_corpus": {"base_commit": "2ed8b010afb59c8b8463ad6818c4ee50fa1f17ee", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "16b5f99d16773ba87cd1a2e40976a2cd3648b75f", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/bin/bat/app.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "4f4a3ddd2adfa985c175bb11", "metadata": {"confidence": "weak", "created_at": "2026-09-04T03:01:41Z", "evidence": {"implementation_files": ["src/bin/bat/app.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-09-04T03:46:32Z", "pr": 3908, "pr_url": "https://github.com/sharkdp/bat/pull/3908"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/bin/bat/app.rs"], "pr_body": "## Problem\n\nFix incorrect detection of `-n` / `-b` when these strings appear in positional arguments or option values.\n\n\n`App::new()` currently scans `wild::args_os()` manually to determine whether `-n` or `-b` was supplied directly on the command line.\n\nThis scan does not implement clap's argument parsing rules. As a result, filenames after `--` and values belonging to short options can be interpreted as numbering flags.\n\nFor example:\n\n```bash\nprintf 'hello\\nworld\\n' > ./-b\nbat -- -b\n```\n\nThe `-b` argument is a filename because it appears after the option terminator. However, the manual scanner treats it as `--number-nonblank`. This can change the output by forcing line numbers and disabling loop-through mode.\n\nA similar problem occurs with short options that accept values:\n\n```bash\nbat -lbn input.txt\n```\n\nHere `bn` is the value of `-l`; it is not a combination of `-b` and `-n`.\n\n\nThe CLI-only flag detection was implemented separately from the clap command used to parse the final arguments. The manual scanner therefore does not handle:\n\n- `--` option terminators;\n- combined short options;\n- short options with attached values;\n- future changes to the argument definitions.\n\n## Solution\n\nParse the original CLI arguments once with the existing clap command and use the resulting `ArgMatches` to determine whether `number` or `number-nonblank` was supplied directly by the user.\n\nThe existing config-file and environment-variable merging logic remains unchanged. The separately parsed matches are only used for CLI-only detection.", "pr_title": "Use parsed CLI arguments to detect number flags"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "618496288c41da835683ec149432c4869722779f", "candidate_corpus": {"base_commit": "618496288c41da835683ec149432c4869722779f", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "e57b547eb95de74b73b34719dd5926254a085634", "negative_distractors": [], "related_tests": ["axum/src/routing/tests/mod.rs"], "root_cause_files": ["axum/src/routing/route.rs"], "root_cause_symbols": [], "supporting_files": ["axum/CHANGELOG.md"]}, "id": "932c8f0e45dec14c7ab3d743", "metadata": {"confidence": "weak", "created_at": "2026-09-28T21:51:34Z", "evidence": {"implementation_files": ["axum/src/routing/route.rs"], "related_tests": ["axum/src/routing/tests/mod.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-10-11T11:54:49Z", "pr": 3907, "pr_url": "https://github.com/tokio-rs/axum/pull/3907"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["axum/src/routing/route.rs"], "pr_body": "## Motivation\n\nFor a 2xx response to `CONNECT`, `RouteFuture` quotes RFC 9110:\n\n> A server MUST NOT send any Transfer-Encoding or Content-Length header fields in a 2xx (Successful) response to CONNECT.\n\nIt then replaces the body with `Body::empty()` but leaves the `Content-Length` and `Transfer-Encoding` headers in place. The response the router returns still carries the forbidden headers.\n\nhyper's HTTP/1 encoder already drops these headers on the wire. Anything else that sees the response after the router still gets them: outer middleware, tests that call the router with `oneshot`, and servers that don't use hyper's HTTP/1 path.\n\n## Solution\n\nRemove `Content-Length` and `Transfer-Encoding` in the same branch that empties the body. I added a regression test, `successful_connect_drops_body_and_framing_headers`, which fails without the change.", "pr_title": "axum: Remove framing headers from successful CONNECT responses"}, "query_provenance": "pr_summary", "repo": "tokio-rs/axum", "task_type": "code2test", "version": 2} +{"base_commit": "96dd4b60e3a7c647c43a85ad375afa690b3bb85b", "candidate_corpus": {"base_commit": "96dd4b60e3a7c647c43a85ad375afa690b3bb85b", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "fe55a131c2780fa856464ad04d7d6dc8a1079b72", "negative_distractors": [], "related_tests": ["tests/test_progress.py"], "root_cause_files": ["rich/progress.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "CONTRIBUTORS.md"]}, "id": "be43d9dce5a7179a4d2df2aa", "metadata": {"confidence": "weak", "created_at": "2025-12-03T21:52:48Z", "evidence": {"implementation_files": ["rich/progress.py"], "related_tests": ["tests/test_progress.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-01-23T10:36:23Z", "pr": 3905, "pr_url": "https://github.com/Textualize/rich/pull/3905"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 1, "implementation_files": ["rich/progress.py"], "pr_body": "Don't output extraneous blank line when progress display is disabled\n\n\n\n\n\n\n## Type of changes\n\n- [x] Bug fix\n- [ ] New feature\n- [ ] Documentation / docstrings\n- [ ] Tests\n- [ ] Other\n\n## AI?\n\n- [ ] AI was used to generate this PR\n\nAI generated PRs may be accepted, but only if @willmcgugan has responded on an issue or discussion.\n\n## Checklist\n\n- [x] I've run the latest [black](https://github.com/psf/black) with default args on new code.\n- [x] I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate (see note about typos above).\n- [x] I've added tests for new code.\n- [x] I accept that @willmcgugan may be pedantic in the code review.\n\n## Description\n\nWhen creating a `Progress` with `disabled=True`, it still outputs a blank line on non interactive consoles. This PR adds an `if not self.disable` to the `stop` function, symmetrically to the `start` function.\n\n**Important:** Link to an issue or discussion regarding these changes. \n\nhttps://github.com/Textualize/rich/issues/110", "pr_title": "Update progress.py"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "0acf9417cd6d9635d927dda9f8e6ab5e57176fa4", "candidate_corpus": {"base_commit": "0acf9417cd6d9635d927dda9f8e6ab5e57176fa4", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "66ad54c27dad68669bf7600722c3e27ceccec2c3", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/bin/bat/app.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "673170e64f388c88a6bcf9ee", "metadata": {"confidence": "weak", "created_at": "2026-08-28T14:22:07Z", "evidence": {"implementation_files": ["src/bin/bat/app.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-09-03T18:52:16Z", "pr": 3897, "pr_url": "https://github.com/sharkdp/bat/pull/3897"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/bin/bat/app.rs"], "pr_body": "## Summary\n\nUse the last occurrence of `-p`, `-n`, and `-b` when determining the effective option in combined short arguments.\n\nThe raw argument scanner currently uses `Iterator::position`, which finds the first occurrence of each flag. This works for combinations such as `-pn` and `-np`, but produces incorrect results when a flag occurs more than once.\n\nFor example, `-npn` ends with `-n`, so numbering should be enabled. The scanner currently compares the first `n` with `p` and incorrectly allows the loop-through printer to be selected, which drops the requested line numbers.\n\nThe same issue affects `-b` combinations:\n\n- `-pbp` should use plain output.\n- `-bpb` should number non-blank lines.\n\n`-pnp` already produces plain output through clap's option handling, but the raw scan still selects the wrong internal printing path.\n\nSwitch the scans to `rposition()` and add regression coverage for all four combinations. The existing rule that `-b` takes precedence over `-n` remains unchanged.\n\n## Tests\n\n- `cargo test --test integration_tests`\n- `cargo fmt --all -- --check`", "pr_title": "fix: use last occurrence in combined short flags"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "4d6d631a3d2deddf8405522d4b8c976a6d35726c", "candidate_corpus": {"base_commit": "4d6d631a3d2deddf8405522d4b8c976a6d35726c", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "12eeb42c96a7a953865b19da204dea6fe658713b", "negative_distractors": [], "related_tests": ["tests/test_inspect.py"], "root_cause_files": ["rich/_inspect.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "CONTRIBUTORS.md"]}, "id": "829218c6dfd271b80acc7df3", "metadata": {"confidence": "weak", "created_at": "2025-11-23T13:47:06Z", "evidence": {"implementation_files": ["rich/_inspect.py"], "related_tests": ["tests/test_inspect.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-01-23T11:47:26Z", "pr": 3894, "pr_url": "https://github.com/Textualize/rich/pull/3894"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 1, "implementation_files": ["rich/_inspect.py"], "pr_body": "## Type of changes\n\n- [x] Bug fix\n- [ ] New feature\n- [ ] Documentation / docstrings\n- [x] Tests\n- [ ] Other\n\n## Checklist\n\n- [x] I've run the latest [black](https://github.com/psf/black) with default args on new code.\n- [x] I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate (see note about typos above).\n- [x] I've added tests for new code.\n- [x] I accept that @willmcgugan may be pedantic in the code review.\n\n## Description\n\nI discovered, that an object with an unusual `__qualname__` attribute (not a `str`, e.g. a descriptor) causes `inspect` to fail.\nThis can happen if an object is created this way intentionally, but I discovered it, when decorating a class with `@functools.lru_cache` which forwards the underlying attributes using a descriptor when it can't add the to it's `__dict__` because the class uses `__slots__`:\n\n```python\nfrom functools import lru_cache\nfrom rich import inspect\n\n\n@lru_cache\nclass Klaas:\n __slots__ = (\"__qualname__\",)\n\n\nif __name__ == \"__main__\":\n from rich.traceback import install\n\n install()\n\n inspect(Klaas.__qualname__)\n inspect(Klaas, all=True)\n```\n\nI fixed it by checking the type of `__qualname__` falling back to `__name__` and if that isn't a `str` using the already provided fallback.", "pr_title": "Handle unusual __qualname__ in inspect"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "4d6d631a3d2deddf8405522d4b8c976a6d35726c", "candidate_corpus": {"base_commit": "4d6d631a3d2deddf8405522d4b8c976a6d35726c", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "abd5a2afc41ff1196fe4d901b8784bb08acf3140", "negative_distractors": [], "related_tests": ["tests/test_prompt.py"], "root_cause_files": ["rich/prompt.py"], "root_cause_symbols": [], "supporting_files": []}, "id": "1842a1cb3b505c9b6ca2fab5", "metadata": {"confidence": "weak", "created_at": "2025-11-13T07:17:55Z", "evidence": {"implementation_files": ["rich/prompt.py"], "related_tests": ["tests/test_prompt.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-01-23T11:48:30Z", "pr": 3882, "pr_url": "https://github.com/Textualize/rich/pull/3882"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["rich/prompt.py"], "pr_body": "## Type of changes\n\n- [x] Bug fix\n- [ ] New feature\n- [ ] Documentation / docstrings\n- [ ] Tests\n- [ ] Other\n\n## Checklist\n\n- [x] I've run the latest [black](https://github.com/psf/black) with default args on new code.\n- [ ] I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate (see note about typos above).\n- [x] I've added tests for new code.\n- [x] I accept that @willmcgugan may be pedantic in the code review.\n\n## Description\n\nPromptBase.on_validate_error() should explicitly ask for markup in case the console passed to it has markup disabled globally.\n\nFixes #3881.", "pr_title": "Fix raw markup printed on prompt errors sometimes"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "66ad54c27dad68669bf7600722c3e27ceccec2c3", "candidate_corpus": {"base_commit": "66ad54c27dad68669bf7600722c3e27ceccec2c3", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "2ed8b010afb59c8b8463ad6818c4ee50fa1f17ee", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/input.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "a8a5f2661ee3d56718098513", "metadata": {"confidence": "weak", "created_at": "2026-08-02T08:53:20Z", "evidence": {"implementation_files": ["src/input.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-09-03T19:07:15Z", "pr": 3877, "pr_url": "https://github.com/sharkdp/bat/pull/3877"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/input.rs"], "pr_body": "## Summary\n\n- inspect up to the first 1024 already-buffered bytes before splitting out the first line\n- preserve the reader's bytes, line boundaries, UTF-16 handling, and streaming behavior\n- add regressions for cross-line binary detection, the 1024-byte boundary, single-read/EOF inputs, and the CLI binary header\n\nFixes #3554.\n\n## Root cause\n\n`content_inspector` checks up to 1024 bytes for a NUL byte, but bat passed only the first line. Random or encrypted data can contain a newline before its first NUL byte, so the shortened sample was classified as UTF-8 and binary bytes were sent to the terminal.\n\nThe fix snapshots the already-buffered prefix with `BufRead::fill_buf()` before `read_until` splits out the first line. The snapshot is non-consuming, so no bytes are lost or reordered, and it does not add a post-line blocking read. Empty input is handled without requesting a second EOF event.\n\n## Compatibility\n\nBOM detection still takes precedence, so UTF-16 input handling is unchanged. ZIP signature detection is also unchanged.\n\nPR #3763 changes the same input initialization path for a distinct issue (#2262: bounding reads for newline-free binary files). If it merges first, this PR will need a small rebase, but the behaviors are complementary.\n\n## Validation\n\n- `cargo test --all-targets --all-features` — clean run: 455 passed, 5 ignored\n- `cargo clippy --all-targets --all-features -- -D warnings`\n- `cargo fmt --check`\n- `git diff --check`", "pr_title": "Detect binary content beyond the first line"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "af59a3218303837421ce06bb2dc3c545525bba0f", "candidate_corpus": {"base_commit": "af59a3218303837421ce06bb2dc3c545525bba0f", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "b671e53c2cd0177beb357cf6cb997ee4215c7155", "negative_distractors": ["src/controller.rs", "src/decorations.rs", "src/printer.rs"], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/bin/bat/app.rs", "src/bin/bat/clap_app.rs", "src/config.rs", "src/controller.rs", "src/decorations.rs", "src/printer.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "doc/long-help.txt", "doc/short-help.txt"]}, "id": "b716fc6d9ec029b717b8c16f", "metadata": {"confidence": "weak", "created_at": "2026-07-24T16:57:08Z", "evidence": {"implementation_files": ["src/bin/bat/app.rs", "src/bin/bat/clap_app.rs", "src/config.rs", "src/controller.rs", "src/decorations.rs", "src/printer.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-08-11T14:39:20Z", "pr": 3857, "pr_url": "https://github.com/sharkdp/bat/pull/3857"}, "query": {"changed_file_summary": "6 implementation files and 1 existing test files changed within 10 total files.", "implementation_file_count": 6, "implementation_files": ["src/bin/bat/app.rs", "src/bin/bat/clap_app.rs", "src/config.rs", "src/controller.rs", "src/decorations.rs", "src/printer.rs"], "pr_body": "Implements `cat -b` compatibility via `-b` / `--number-nonblank`.\n\n### Behaviour\n\n```console\n$ printf 'alpha\\n\\nbeta\\n' | bat -b\n 1 alpha\n \n 2 world\n```\n\n- Non-blank lines are numbered sequentially\n- Blank lines (empty / newline-only) are printed without a number and\n do not advance the line counter\n- Lines containing spaces or tabs are *not* blank and **are** numbered\n- `-b` takes precedence over `-n`; both `-bn` and `-nb` produce nonblank numbering\n- `-bp` disables numbering (plain mode wins)\n\n### Implementation\n\nCore change is in `src/controller.rs`: when `number_nonblank` is set,\nthe line counter is not incremented for lines whose buffer contains\nonly `\\r` / `\\n` bytes. In `src/printer.rs` the decoration engine\nreceives `line_number = 0` as sentinel for those lines, and\n`LineNumberDecoration::generate` returns empty gutter spaces in that\ncase. The raw-arg scanner in `App::new()` was extended to detect `-b`\nthe same way it detects `-n` (so it works with combined short flags\nlike `-pb` / `-bp`).\n\n### Testing\n\n- 5 new integration tests: plain `-b`, `-b` in loop-through mode,\n `-bn`/`-nb` precedence, `-bp` override, piped stdin\n- All 436 existing tests continue to pass\n- Help-text snapshots regenerated\n\nCloses #3856.", "pr_title": "feat: implement `-b` / `--number-nonblank` for `cat -b` compatibility"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "384f2f5d13dbb70b0b75dbc2d911c9012bcc5b09", "candidate_corpus": {"base_commit": "384f2f5d13dbb70b0b75dbc2d911c9012bcc5b09", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "0230cba42d2f1089e232930aae9fccc5ec49cfa3", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/bin/bat/main.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "40a2a1f2a81cbda7e17df735", "metadata": {"confidence": "weak", "created_at": "2026-07-04T03:30:58Z", "evidence": {"implementation_files": ["src/bin/bat/main.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-07-29T20:49:08Z", "pr": 3828, "pr_url": "https://github.com/sharkdp/bat/pull/3828"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/bin/bat/main.rs"], "pr_body": "Fixes #3825.\n\nSummary:\n- Reuse the parsed config when rendering `--list-languages`, while forcing plain style for the generated listing.\n- Add a regression test that `--paging=never` prevents `PAGER` from being invoked.\n\nTests:\n- `cargo test --test integration_tests list_languages -- --exact`", "pr_title": "Respect paging mode for --list-languages"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "835bd2a756b133531a8c49cb2b519654d57ace60", "candidate_corpus": {"base_commit": "835bd2a756b133531a8c49cb2b519654d57ace60", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "bb4f48a124b8a9eb83c9368361ed4b9a9351fe9c", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/assets.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "tests/examples/regression_tests/issue_2745.txt"]}, "id": "f18e42884c73b2f3658277f4", "metadata": {"confidence": "weak", "created_at": "2026-06-30T19:15:58Z", "evidence": {"implementation_files": ["src/assets.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-06-30T21:40:18Z", "pr": 3816, "pr_url": "https://github.com/sharkdp/bat/pull/3816"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 1, "implementation_files": ["src/assets.rs"], "pr_body": "When an ignored suffix is also a registered extension (e.g. `.txt` maps to \"Plain Text\"), `get_syntax_for_file_extension` matched the raw extension before attempting the suffix strip. As a result `--ignored-suffix .txt` had no effect on such files and first-line/shebang detection was never reached, so a shell script saved as `*.txt` stayed unhighlighted.\n\nStrip ignored suffixes first and detect on the remainder; only fall back to the raw extension when no ignored suffix applies. When a suffix is stripped but the remainder has no syntax, return `None` so the caller can use first-line detection. Default behavior (no `--ignored-suffix`) is unchanged.\n\nSee #2745.", "pr_title": "Fix --ignored-suffix to fall back to first-line detection"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "af1f53d9a977154216d01435991fe33631b74713", "candidate_corpus": {"base_commit": "af1f53d9a977154216d01435991fe33631b74713", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "5bb35b4bedc110fb9a37d1ff657d2dbb27863814", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/printer.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "1a81a90cb1da2f31093f2a61", "metadata": {"confidence": "weak", "created_at": "2026-06-16T07:06:06Z", "evidence": {"implementation_files": ["src/printer.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-06-16T17:19:08Z", "pr": 3804, "pr_url": "https://github.com/sharkdp/bat/pull/3804"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/printer.rs"], "pr_body": "Fixes #3803.\n\n`InteractivePrinter::print_snip` computes the snip-separator width as `term_width - panel_count - snip_left_count - title_count`. At `--terminal-width 1` the panel is disabled (`panel_count == 0`, `snip_left_count == 0`) and the `\"8<\"` title gives `title_count == 2`, so the subtraction underflows `usize` (release has no overflow-checks, so it wraps to ~`usize::MAX`); `str::repeat` then aborts with `capacity overflow` whenever a snip separator is emitted — i.e. two or more disjoint line ranges (or a diff gap), which the default style does:\n\n```console\n$ printf 'l1\\nl2\\nl3\\nl4\\nl5\\nl6\\nl7\\nl8\\n' > t.txt\n$ bat --color=always --terminal-width 1 --line-range 1:2 --line-range 7:8 t.txt\nthread 'main' panicked at library/alloc/src/slice.rs:523:50:\ncapacity overflow\n```\n\nThis uses `saturating_sub` for the `repeat` counts so they clamp to `0` instead of underflowing. Normal-width snip rendering is unchanged (the separator dashes are simply omitted at width 1).\n\nAdded an integration test (`snip_at_terminal_width_one_does_not_panic`) and a CHANGELOG entry.", "pr_title": "Fix capacity-overflow panic in snip separator at --terminal-width 1"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "3b70db5a2997de191f7db3e422dbe4da35ca1c95", "candidate_corpus": {"base_commit": "3b70db5a2997de191f7db3e422dbe4da35ca1c95", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "b6aae7c342b23656e8d4559909c8a2efd3a4d7c1", "negative_distractors": [], "related_tests": ["tests/test_syntax.py"], "root_cause_files": ["rich/syntax.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "b53a9668f876021715d51b20", "metadata": {"confidence": "weak", "created_at": "2025-06-23T15:39:57Z", "evidence": {"implementation_files": ["rich/syntax.py"], "related_tests": ["tests/test_syntax.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2025-06-23T16:22:05Z", "pr": 3782, "pr_url": "https://github.com/Textualize/rich/pull/3782"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["rich/syntax.py"], "pr_body": "Fixes https://github.com/Textualize/rich/issues/3727", "pr_title": "Syntax padding"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "65bb66dfdcdb898330d6e0d19729e63adbc5b0da", "candidate_corpus": {"base_commit": "65bb66dfdcdb898330d6e0d19729e63adbc5b0da", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "49117ced6648a432d85951f72dce777038f6ce09", "negative_distractors": [], "related_tests": ["tests/test_console.py"], "root_cause_files": ["rich/_inspect.py"], "root_cause_symbols": [], "supporting_files": []}, "id": "878fc539040e09a2aee4cea8", "metadata": {"confidence": "weak", "created_at": "2025-06-20T14:37:23Z", "evidence": {"implementation_files": ["rich/_inspect.py"], "related_tests": ["tests/test_console.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2025-06-20T14:52:52Z", "pr": 3776, "pr_url": "https://github.com/Textualize/rich/pull/3776"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["rich/_inspect.py"], "pr_body": "## Type of changes\n\n- [ ] Bug fix\n- [ ] New feature\n- [X] Documentation / docstrings\n- [ ] Tests\n- [ ] Other\n\n## Checklist\n\n- [ ] I've run the latest [black](https://github.com/psf/black) with default args on new code.\n- [ ] I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate.\n- [ ] I've added tests for new code.\n- [X] I accept that @willmcgugan may be pedantic in the code review.\n\n## Description\n\nFound and fixed typo in comments", "pr_title": "Fix small typo in comments"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "2809954800af15b4027364cebf82390fe23dc194", "candidate_corpus": {"base_commit": "2809954800af15b4027364cebf82390fe23dc194", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "2a282af76d3f7a731e1c23145e13977044150f1e", "negative_distractors": [], "related_tests": ["tests/test_traceback.py"], "root_cause_files": ["rich/traceback.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "8a9e13453251b4c31a203e80", "metadata": {"confidence": "weak", "created_at": "2025-06-19T08:24:44Z", "evidence": {"implementation_files": ["rich/traceback.py"], "related_tests": ["tests/test_traceback.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2025-06-19T14:39:18Z", "pr": 3772, "pr_url": "https://github.com/Textualize/rich/pull/3772"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["rich/traceback.py"], "pr_body": "Fixes https://github.com/Textualize/rich/issues/3708\nFixes https://github.com/Textualize/rich/issues/3682", "pr_title": "Fix traceback recursion"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "27d923023127ac66359a18b5b02b83c1e534db3e", "candidate_corpus": {"base_commit": "27d923023127ac66359a18b5b02b83c1e534db3e", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "2809954800af15b4027364cebf82390fe23dc194", "negative_distractors": ["rich/align.py", "rich/box.py", "rich/console.py", "rich/control.py", "rich/emoji.py", "rich/live_render.py", "rich/markdown.py", "rich/progress.py"], "related_tests": ["tests/test_syntax.py"], "root_cause_files": ["docs/source/conf.py", "examples/top_lite_simulator.py", "rich/_ratio.py", "rich/align.py", "rich/box.py", "rich/console.py", "rich/control.py", "rich/emoji.py"], "root_cause_symbols": [], "supporting_files": ["rich/live_render.py", "rich/markdown.py", "rich/progress.py", "CHANGELOG.md", "CONTRIBUTORS.md", "poetry.lock", "pyproject.toml"]}, "id": "c92d0d12eb33776016f6ddd3", "metadata": {"confidence": "weak", "created_at": "2025-06-15T15:26:58Z", "evidence": {"implementation_files": ["docs/source/conf.py", "examples/top_lite_simulator.py", "rich/_ratio.py", "rich/align.py", "rich/box.py", "rich/console.py", "rich/control.py", "rich/emoji.py", "rich/live_render.py", "rich/markdown.py", "rich/progress.py"], "related_tests": ["tests/test_syntax.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2025-06-18T17:50:31Z", "pr": 3763, "pr_url": "https://github.com/Textualize/rich/pull/3763"}, "query": {"changed_file_summary": "11 implementation files and 1 existing test files changed within 16 total files.", "implementation_file_count": 11, "implementation_files": ["docs/source/conf.py", "examples/top_lite_simulator.py", "rich/_ratio.py", "rich/align.py", "rich/box.py", "rich/console.py", "rich/control.py", "rich/emoji.py"], "pr_body": "Fixes https://github.com/Textualize/rich/issues/3762\n\n## Type of changes\n\n- [ ] Bug fix\n- [x] New feature\n- [ ] Documentation / docstrings\n- [ ] Tests\n- [ ] Other\n\n## Checklist\n\n- [x] I've run the latest [black](https://github.com/psf/black) with default args on new code.\n- [x] I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate.\n- [x] I've added tests for new code.\n- [x] I accept that @willmcgugan may be pedantic in the code review.\n\n## Description\n\nRemove `typing-extensions` as a runtime dependency by:\n\n1. Removed all `sys.version_info >= (3, 8)` blocks as rich no longer supports Python 3.7\n2. Moved the one remaining `typing_extensions` import into a `TYPE_CHECKING` block\n3. Move `typing-extensions` from a runtime dependency to a dev dependency in the `pyproject.toml` file\n\nI did have some problems running pre-commit locally, hopefully that was just a local issue, I will fix any CI issues if they come up.", "pr_title": "Remove `typing-extensions` as a runtime dependency"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "971f9679dafac7fb9246c2f8a43118873a446b3a", "candidate_corpus": {"base_commit": "971f9679dafac7fb9246c2f8a43118873a446b3a", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "78951393e29bfd2f2a45f4326b9d2bb5e737dd2a", "negative_distractors": ["src/preprocessor.rs", "src/pretty_printer.rs", "src/printer.rs", "src/vscreen.rs"], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/bin/bat/app.rs", "src/bin/bat/clap_app.rs", "src/config.rs", "src/preprocessor.rs", "src/pretty_printer.rs", "src/printer.rs", "src/vscreen.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "README.md", "assets/completions/_bat.ps1.in", "assets/completions/bat.bash.in", "assets/completions/bat.fish.in", "assets/completions/bat.zsh.in", "doc/long-help.txt"]}, "id": "1ddd7bd1278f9fd239e86306", "metadata": {"confidence": "weak", "created_at": "2026-05-06T14:27:42Z", "evidence": {"implementation_files": ["src/bin/bat/app.rs", "src/bin/bat/clap_app.rs", "src/config.rs", "src/preprocessor.rs", "src/pretty_printer.rs", "src/printer.rs", "src/vscreen.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-07-01T20:15:58Z", "pr": 3729, "pr_url": "https://github.com/sharkdp/bat/pull/3729"}, "query": {"changed_file_summary": "7 implementation files and 1 existing test files changed within 15 total files.", "implementation_file_count": 7, "implementation_files": ["src/bin/bat/app.rs", "src/bin/bat/clap_app.rs", "src/config.rs", "src/preprocessor.rs", "src/pretty_printer.rs", "src/printer.rs", "src/vscreen.rs"], "pr_body": "This adds an alias for `--strip-ansi` and enforces more strict sanitation.\n\n`--strip-ansi` is currently the only option to handle untrusted data, but the name is confusing and does not fully reflect what the code does and it is also incomplete for the purpose of sanitation.\n\nThis PR adds an **alternative** to the `--strip-ansi` option named `--sanitize`\nit extends the filtered characters to cover all relevant sequences that could spoof content or trigger terminal commands.\n\nSpecifically the added changes are:\n\n- Parse 8-bit C1 introducers and DCS/SOS/PM/APC bodies (the #3725 fix).\n- Substitute bare CR with U+FFFD (`�`) (line-overwrite forgery).\n- Substitute SO/SI with U+FFFD (`�`) (charset-shift forgery).\n- Substitute non-introducer 8-bit C1 controls with U+FFFD (`�`) (RI is a cursor-up overwrite vector).\n- Substitute the remaining C0 controls and DEL (BEL, BS, VT, CAN, SUB, …) with U+FFFD (`�`).\n- Substitute Unicode bidi and zero-width formatting characters (U+200B–U+200D, U+202A–U+202E, U+2066–U+2069, U+FEFF) with U+FFFD (`�`) (content-spoofing / Trojan-Source vector).\n\nCRLF, FF, tab, newline pass through unchanged. `auto`-mode plain-text carve-out preserved. Loop-through cat-mode preserved.", "pr_title": "add --sanitize option"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "7be02d77545cb918ad2f6b9b62c81fe769afaab6", "candidate_corpus": {"base_commit": "7be02d77545cb918ad2f6b9b62c81fe769afaab6", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "309d1bd9530eec2217134cb262760af1df42ee3b", "negative_distractors": [], "related_tests": ["axum-macros/tests/debug_handler/fail/single_wrong_return_tuple.stderr", "axum-macros/tests/debug_handler/fail/wrong_return_tuple.stderr", "axum-macros/tests/debug_handler/fail/wrong_return_type.stderr"], "root_cause_files": ["axum-core/src/response/into_response.rs", "axum-core/src/response/into_response_parts.rs"], "root_cause_symbols": [], "supporting_files": []}, "id": "40aa117ddfaf42d421866eaf", "metadata": {"confidence": "weak", "created_at": "2026-04-12T09:12:39Z", "evidence": {"implementation_files": ["axum-core/src/response/into_response.rs", "axum-core/src/response/into_response_parts.rs"], "related_tests": ["axum-macros/tests/debug_handler/fail/single_wrong_return_tuple.stderr", "axum-macros/tests/debug_handler/fail/wrong_return_tuple.stderr", "axum-macros/tests/debug_handler/fail/wrong_return_type.stderr"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-04-15T11:06:41Z", "pr": 3723, "pr_url": "https://github.com/tokio-rs/axum/pull/3723"}, "query": {"changed_file_summary": "2 implementation files and 3 existing test files changed within 5 total files.", "implementation_file_count": 2, "implementation_files": ["axum-core/src/response/into_response.rs", "axum-core/src/response/into_response_parts.rs"], "pr_body": "## Motivation\n\nThe `FromRequest`, `FromRequestParts`, and `Handler` traits already use `#[diagnostic::on_unimplemented]` to provide helpful compiler messages when users encounter trait bound errors. However, `IntoResponse` and `IntoResponseParts` — two of the most commonly encountered traits in error messages — lack this attribute.\n\nWhen users forget to implement `IntoResponse` on their custom response types (or return types that don't implement it), the compiler shows a bare \"trait bound not satisfied\" error without guidance.\n\n## Solution\n\nAdd `#[diagnostic::on_unimplemented]` to both `IntoResponse` and `IntoResponseParts` traits in `axum-core`, with links to the relevant documentation pages. This matches the existing pattern used by the extractor and handler traits.", "pr_title": "feat: add `#[diagnostic::on_unimplemented]` to `IntoResponse` and `IntoResponseParts`"}, "query_provenance": "pr_summary", "repo": "tokio-rs/axum", "task_type": "code2test", "version": 2} +{"base_commit": "7d36119f8378b36129502c3281a7faffef837e02", "candidate_corpus": {"base_commit": "7d36119f8378b36129502c3281a7faffef837e02", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "21b3800894f6a81d3f68a0e34796be67e3ccd39f", "negative_distractors": [], "related_tests": ["tests/test_panel.py"], "root_cause_files": ["rich/panel.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "ff6dec5964d0af994ca462c8", "metadata": {"confidence": "weak", "created_at": "2025-05-01T21:13:15Z", "evidence": {"implementation_files": ["rich/panel.py"], "related_tests": ["tests/test_panel.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2025-06-24T12:18:52Z", "pr": 3718, "pr_url": "https://github.com/Textualize/rich/pull/3718"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["rich/panel.py"], "pr_body": "Fix `Panel` title missing the panel background style.\n \nThis really just reverts the change in 7a38204. There's a history of issues related to the panel title styles, so I was careful to run all the examples in those issues to ensure there wasn't any regression.\n \nFixes #3569\n\n## Type of changes\n\n- [x] Bug fix\n- [ ] New feature\n- [ ] Documentation / docstrings\n- [ ] Tests\n- [ ] Other\n\n## Checklist\n\n- [x] I've run the latest [black](https://github.com/psf/black) with default args on new code.\n- [x] I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate.\n- [x] I've added tests for new code.\n- [x] I accept that @willmcgugan may be pedantic in the code review.", "pr_title": "fix(panel): fix title missing panel background"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "04576fd5a59acd3c223f042a8e9e4aaa4b1d09f1", "candidate_corpus": {"base_commit": "04576fd5a59acd3c223f042a8e9e4aaa4b1d09f1", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "8f70e0cf00e1bca04df97669d5b50b9bf4608746", "negative_distractors": [], "related_tests": ["tests/tester/mod.rs"], "root_cause_files": ["src/diff.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "Cargo.lock", "Cargo.toml"]}, "id": "6d1b087903f226d020266310", "metadata": {"confidence": "weak", "created_at": "2026-04-26T20:07:17Z", "evidence": {"implementation_files": ["src/diff.rs"], "related_tests": ["tests/tester/mod.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-06-27T02:53:22Z", "pr": 3703, "pr_url": "https://github.com/sharkdp/bat/pull/3703"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 5 total files.", "implementation_file_count": 1, "implementation_files": ["src/diff.rs"], "pr_body": "This is a continuation of https://github.com/sharkdp/bat/pull/3235\n\nThis time all tests pass without any changes :D Looks promising!\n\n**Context**: This PR replaces the usage of `libgit2` with a full Rust implementation of `git`. This was tried [before](https://github.com/sharkdp/bat/pull/3235) but a couple of issues were found in the Rust implementation of `git`. These issues seem to be fixed now. Therefore, I am opening this again and would like to see what the maintainers think. \n\nCC: @byron", "pr_title": "Replace libgit2 with gitoxide (#2)"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "a995764d230e49e089febd8e5487c1d61e5d3051", "candidate_corpus": {"base_commit": "a995764d230e49e089febd8e5487c1d61e5d3051", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "33045c35582cc20f3a0c27dd092884c6eec42373", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/bin/bat/clap_app.rs", "src/bin/bat/config.rs", "src/bin/bat/main.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "doc/long-help.txt"]}, "id": "6124e7429d105a3a449333f5", "metadata": {"confidence": "weak", "created_at": "2026-04-10T14:36:37Z", "evidence": {"implementation_files": ["src/bin/bat/clap_app.rs", "src/bin/bat/config.rs", "src/bin/bat/main.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-04-12T01:59:03Z", "pr": 3687, "pr_url": "https://github.com/sharkdp/bat/pull/3687"}, "query": {"changed_file_summary": "3 implementation files and 1 existing test files changed within 6 total files.", "implementation_file_count": 3, "implementation_files": ["src/bin/bat/clap_app.rs", "src/bin/bat/config.rs", "src/bin/bat/main.rs"], "pr_body": "## Summary\n- add `BAT_WIDTH` as an environment-backed alias for `--terminal-width`\n- surface `BAT_WIDTH` in `--diagnostic` output and the terminal-width help text\n- add integration coverage for env-driven width selection and normal CLI override precedence\n\n## Testing\n- `cargo test --lib`\n- `cargo test --test integration_tests`\n\nCloses #3679", "pr_title": "Support BAT_WIDTH for terminal width"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "111aa2e10e7a7f0dcf43c209e643593ac013d623", "candidate_corpus": {"base_commit": "111aa2e10e7a7f0dcf43c209e643593ac013d623", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "a995764d230e49e089febd8e5487c1d61e5d3051", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/input.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "85b800b36dcf18935654d946", "metadata": {"confidence": "weak", "created_at": "2026-04-10T14:36:37Z", "evidence": {"implementation_files": ["src/input.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-04-10T17:30:27Z", "pr": 3686, "pr_url": "https://github.com/sharkdp/bat/pull/3686"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/input.rs"], "pr_body": "## Summary\n- keep the existing `content_inspector` path and add a narrow ZIP magic fallback when it would otherwise classify archive bytes as UTF-8 text\n- treat the standard ZIP signatures (`PK\\x03\\x04`, `PK\\x05\\x06`, `PK\\x07\\x08`) as binary content\n- add unit and integration regressions covering ZIP detection without changing other PK-prefixed text\n\n## Testing\n- `cargo test --lib`\n- `cargo test --test integration_tests`\n\nCloses #3663", "pr_title": "Detect ZIP archives as binary content"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "1932d1da39b445ae56db4081c9d3ead3260fa5ed", "candidate_corpus": {"base_commit": "1932d1da39b445ae56db4081c9d3ead3260fa5ed", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "a1e7c0ab4ae87d388e2f2922a25f15b4ca5f62de", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/bin/bat/app.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "0e54d0c0499ce8c859921456", "metadata": {"confidence": "weak", "created_at": "2026-03-20T04:36:04Z", "evidence": {"implementation_files": ["src/bin/bat/app.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-03-21T14:30:43Z", "pr": 3643, "pr_url": "https://github.com/sharkdp/bat/pull/3643"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/bin/bat/app.rs"], "pr_body": "## Summary\n\nWhen `--plain` is set (via CLI or config file), `--diff` output loses all visual markers - no `~`/`+`/`-` change indicators and no `Snip` separators between hunks. The diff line filtering still works (only changed regions are shown), but the output is indistinguishable from plain text.\n\nThe root cause is `forced_style_components()` which returns early with only `StyleComponent::Plain` (resolving to an empty decoration set) before `--style` arguments can be parsed. The user's workaround of adding `--style=full` also fails because forced components take priority.\n\n### Fix\n\nWhen `--plain` is set AND `--diff` is also active, automatically include `Changes` and `Snip` style components. This preserves the `--plain` intent (no grid, no header, no line numbers) while keeping diff output readable.\n\n**Note:** This is a behavior change. I'd welcome feedback on whether this automatic approach is preferred, or if an alternative like a warning message or a new dedicated style component would be better.\n\n## Test plan\n\n- [ ] `bat --diff --plain file.c` shows change markers and snip separators\n- [ ] `bat --plain file.c` (without --diff) behavior is unchanged\n- [ ] `bat --diff file.c` (without --plain) behavior is unchanged\n- [ ] Works when `--plain` is set via `BAT_CONFIG_FILE`\n- [ ] `cargo test` passes\n- [ ] `cargo clippy` clean\n\nCloses #3630\n\nThis contribution was developed with AI assistance (Claude Code).", "pr_title": "feat: preserve change markers when combining --diff with --plain"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "4a38eab3eaa191a6a19239bde42f7d5b79d7cb21", "candidate_corpus": {"base_commit": "4a38eab3eaa191a6a19239bde42f7d5b79d7cb21", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "f2daa1eb6e2bb21366d856ca9e160698a69fd8eb", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/printer.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "tests/examples/regression_tests/issue_3631.txt"]}, "id": "5a607d6bbcc38ebca218a397", "metadata": {"confidence": "weak", "created_at": "2026-03-19T16:10:27Z", "evidence": {"implementation_files": ["src/printer.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-03-20T20:40:28Z", "pr": 3640, "pr_url": "https://github.com/sharkdp/bat/pull/3640"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 1, "implementation_files": ["src/printer.rs"], "pr_body": "Control characters (0x00-0x1F, 0x7F) render as two-column caret notation (^@, ^A, ..., ^?) in the terminal, but `UnicodeWidthChar::width()` returns `None` for them. The wrapping code defaulted to width 0, so wrapping was off for any line with control chars.\n\nReplace the `c.width().unwrap_or(0)` calls with a `char_width()` helper that returns 2 for control characters.\n\nFixes #3631", "pr_title": "Fix line wrapping for files with control characters"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "ab80bd9717448d988445841fc9634e7d7c2f8cf6", "candidate_corpus": {"base_commit": "ab80bd9717448d988445841fc9634e7d7c2f8cf6", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "844bfded506e99c06237472bd83a8af5af433538", "negative_distractors": ["src/config.rs", "src/printer.rs"], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/assets.rs", "src/bin/bat/app.rs", "src/bin/bat/clap_app.rs", "src/config.rs", "src/printer.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "doc/long-help.txt", "doc/short-help.txt"]}, "id": "114d2d60f6fda484dd06a66a", "metadata": {"confidence": "weak", "created_at": "2026-03-07T20:32:54Z", "evidence": {"implementation_files": ["src/assets.rs", "src/bin/bat/app.rs", "src/bin/bat/clap_app.rs", "src/config.rs", "src/printer.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-03-08T03:18:29Z", "pr": 3617, "pr_url": "https://github.com/sharkdp/bat/pull/3617"}, "query": {"changed_file_summary": "5 implementation files and 1 existing test files changed within 9 total files.", "implementation_file_count": 5, "implementation_files": ["src/assets.rs", "src/bin/bat/app.rs", "src/bin/bat/clap_app.rs", "src/config.rs", "src/printer.rs"], "pr_body": "## Summary\n- add a new `--fallback-syntax` CLI option (with alias `--fallback-language`) and wire it into config parsing\n- apply the fallback only when syntax auto-detection fails (after path + first-line detection), without changing `--language` behavior\n- add integration tests for fallback behavior/precedence and update short/long help expectation docs\n\n## Validation\n- `cargo build`\n- `cargo test`", "pr_title": "Add --fallback-syntax for undetected files"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "fbc05da785ec5e728d60762a282b5d96a578bfd2", "candidate_corpus": {"base_commit": "fbc05da785ec5e728d60762a282b5d96a578bfd2", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "594069581de331f15329129538ba4967ea469f81", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/bin/bat/app.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "77fc22e1aab6623f195319fc", "metadata": {"confidence": "weak", "created_at": "2026-02-20T06:04:55Z", "evidence": {"implementation_files": ["src/bin/bat/app.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-02-20T18:26:23Z", "pr": 3592, "pr_url": "https://github.com/sharkdp/bat/pull/3592"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/bin/bat/app.rs"], "pr_body": "fixes #3587\n\n--wrap=never and -S flags were ignored when bat piped to a pager because the code didn't check explicit flags before defaulting based on interactivity\n\nnow checks explicit wrap flags first, then falls back to interactive logic only for auto mode\n\ntested with new regression tests, all existing tests pass", "pr_title": "respect --wrap=never flag when piping to pager"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "594069581de331f15329129538ba4967ea469f81", "candidate_corpus": {"base_commit": "594069581de331f15329129538ba4967ea469f81", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "7d7e202bd56818ac81a7ed892f165b546993dd86", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/output.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "72f245a8a323b65fd9fed476", "metadata": {"confidence": "weak", "created_at": "2026-02-19T20:56:57Z", "evidence": {"implementation_files": ["src/output.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-02-20T18:46:38Z", "pr": 3588, "pr_url": "https://github.com/sharkdp/bat/pull/3588"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/output.rs"], "pr_body": "fixes #2904\n\nbat was silently falling back to stdout when the pager wasn't found, which confused users who expected output to be paged\n\nnow shows a clear warning message when the pager is missing but still works by falling back to stdout\n\ntested with nonexistent pager, real pager, and all existing tests pass", "pr_title": "warn when pager is missing instead of silently falling back"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "cb8b6375747241e45ac129278b0fc8f8e0979699", "candidate_corpus": {"base_commit": "cb8b6375747241e45ac129278b0fc8f8e0979699", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "990b2fc06f6d5458df1ff222e7ed59c371ce1c46", "negative_distractors": ["src/controller.rs", "src/input.rs", "src/output.rs"], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/bin/bat/app.rs", "src/bin/bat/clap_app.rs", "src/config.rs", "src/controller.rs", "src/input.rs", "src/output.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "assets/completions/_bat.ps1.in", "assets/completions/bat.bash.in", "assets/completions/bat.fish.in", "assets/completions/bat.zsh.in", "assets/manual/bat.1.in", "doc/long-help.txt", "doc/short-help.txt"]}, "id": "8e7fdceec585f153ba93023a", "metadata": {"confidence": "weak", "created_at": "2026-02-12T04:40:07Z", "evidence": {"implementation_files": ["src/bin/bat/app.rs", "src/bin/bat/clap_app.rs", "src/config.rs", "src/controller.rs", "src/input.rs", "src/output.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-02-12T06:40:44Z", "pr": 3583, "pr_url": "https://github.com/sharkdp/bat/pull/3583"}, "query": {"changed_file_summary": "6 implementation files and 1 existing test files changed within 15 total files.", "implementation_file_count": 6, "implementation_files": ["src/bin/bat/app.rs", "src/bin/bat/clap_app.rs", "src/config.rs", "src/controller.rs", "src/input.rs", "src/output.rs"], "pr_body": "## Summary\n\nCloses #3555.\n\n- Repurpose the existing `--unbuffered`/`-u` flag (previously a POSIX no-op) to enable unbuffered input reading using `fill_buf()`/`consume()` instead of `read_until(b'\\n')`\n- Partial lines display immediately when piping streaming input like `tail -f` into bat\n- Line numbers are auto-disabled in unbuffered mode to avoid confusion with partial lines\n\n## Implementation\n\n- **`src/input.rs`**: Added `read_line_unbuffered()` method to `InputReader` that uses `BufRead::fill_buf()`/`consume()` to return whatever data is available without waiting for a newline. First line still blocks for content type detection.\n- **`src/output.rs`**: Added `flush()` to `OutputHandle` so output is flushed after each line in unbuffered mode.\n- **`src/controller.rs`**: Wires the unbuffered flag from config to the input reader, and flushes after each printed line.\n- **`src/bin/bat/app.rs`** / **`src/bin/bat/clap_app.rs`**: Reads the `--unbuffered` flag, auto-strips `LineNumbers` style component, updated help text.\n- **Documentation**: Updated man page, help text snapshots, and all shell completions (bash, fish, zsh, PowerShell).\n\n## Trade-offs\n\n- Syntax highlighting may be imperfect on partial lines (acceptable for streaming use case)\n- First line still blocks (needed for content type detection)\n\n## Test plan\n\n- [x] `cargo build` compiles cleanly\n- [x] `cargo test` — all 362 tests pass (212 integration + 114 unit + others)\n- [x] 3 new unit tests for unbuffered reading (partial data, complete lines, EOF)\n- [x] 3 new integration tests (flag accepted, line numbers disabled, plain output)\n- [x] Manual streaming test: `tail -f logfile | bat --unbuffered --paging=never` shows partial lines immediately\n- [x] Normal (non-unbuffered) mode unchanged", "pr_title": "feat: implement --unbuffered mode for streaming input"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "391e7ff072e9349dd7d2f695d84f0650e895a183", "candidate_corpus": {"base_commit": "391e7ff072e9349dd7d2f695d84f0650e895a183", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "cb8b6375747241e45ac129278b0fc8f8e0979699", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/bin/bat/clap_app.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "95ae778259d3560405372471", "metadata": {"confidence": "weak", "created_at": "2026-02-06T13:05:15Z", "evidence": {"implementation_files": ["src/bin/bat/clap_app.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "cross_directory_test"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-02-09T03:06:41Z", "pr": 3580, "pr_url": "https://github.com/sharkdp/bat/pull/3580"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/bin/bat/clap_app.rs"], "pr_body": "## Summary\n\nFixes #3560\n\n## Problem\n\n`bat cache --help` currently fails with:\n\n```\nerror: unexpected argument '--help' found\n\nUsage: bat cache [OPTIONS] <--build|--clear>\n```\n\nThis happens because the `cache-actions` ArgGroup is set to `required(true)`, which causes clap to validate required arguments before processing the `--help` flag.\n\n## Solution\n\nRemove `.required(true)` from the `cache-actions` ArgGroup. The behavior remains the same (users must specify either `--build` or `--clear` when running the cache subcommand) because clap will still show an error if neither is provided. However, now `--help` is processed first, allowing users to view the help message.\n\n## Testing\n\n```bash\n# Before: error\n$ bat cache --help\nerror: unexpected argument '--help' found\n\n# After: shows help\n$ bat cache --help\nModify the syntax-definition and theme cache\n...\n```\n\n---\n\n*This is a resubmission of #3573 with `cargo fmt` applied.*", "pr_title": "fix(cache): allow --help flag for cache subcommand"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "3d0a7ed0a0e5252f2bd43099ffb39514e60d775f", "candidate_corpus": {"base_commit": "3d0a7ed0a0e5252f2bd43099ffb39514e60d775f", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "8664cc9df9ace1d3813fd4fd87f42e2327232936", "negative_distractors": ["src/printer.rs"], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/bin/bat/app.rs", "src/bin/bat/clap_app.rs", "src/config.rs", "src/printer.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "assets/completions/_bat.ps1.in", "assets/completions/bat.bash.in", "assets/completions/bat.fish.in", "assets/completions/bat.zsh.in", "assets/manual/bat.1.in", "doc/long-help.txt", "doc/short-help.txt"]}, "id": "29ba5dec8ba294f1af9beb26", "metadata": {"confidence": "weak", "created_at": "2026-01-31T08:42:41Z", "evidence": {"implementation_files": ["src/bin/bat/app.rs", "src/bin/bat/clap_app.rs", "src/config.rs", "src/printer.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-02-01T09:15:45Z", "pr": 3563, "pr_url": "https://github.com/sharkdp/bat/pull/3563"}, "query": {"changed_file_summary": "4 implementation files and 1 existing test files changed within 13 total files.", "implementation_file_count": 4, "implementation_files": ["src/bin/bat/app.rs", "src/bin/bat/clap_app.rs", "src/config.rs", "src/printer.rs"], "pr_body": "## Summary\n\nThis PR adds a `--quiet-empty` (`-E`) flag that suppresses all output when the input is empty.\n\n## Motivation\n\nCloses #1936\n\nWhen using `bat` in pipelines with commands that may produce empty output (like `git diff` when there are no changes), the current behavior shows:\n\n```\n───────┬──────────────────\n │ STDIN \n───────┴──────────────────\n```\n\nThis can be noisy and unexpected. With `--quiet-empty`, users can opt for no output at all when input is empty.\n\n## Changes\n\n- Added `quiet_empty: bool` field to `Config`\n- Added `--quiet-empty` / `-E` CLI flag in `clap_app.rs`\n- Wired up the config in `app.rs`\n- Implemented the behavior in `printer.rs` by checking `content_type.is_none()` in `print_header` and `print_footer`\n- Added CHANGELOG entry\n- Added integration tests\n\n## Usage\n\n```bash\n# No output when input is empty\necho \"\" | bat --quiet-empty\n\n# Useful with git diff\ngit diff | bat --quiet-empty\n\n# Can be set via BAT_OPTS environment variable\nexport BAT_OPTS=\"--quiet-empty\"\n```\n\n## Testing\n\nAdded 3 integration tests:\n- `quiet_empty_suppresses_output_on_empty_stdin`\n- `quiet_empty_does_not_affect_non_empty_input`\n- `quiet_empty_suppresses_output_on_empty_file`", "pr_title": "feat: add --quiet-empty flag to suppress output on empty input"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "0f2f51b872d14588de3a65968f5cdde6fb5694a3", "candidate_corpus": {"base_commit": "0f2f51b872d14588de3a65968f5cdde6fb5694a3", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "afcc5c5a957c75b325fd7cc45bd70b3ac6413ef4", "negative_distractors": [], "related_tests": ["tests/test_cells.py"], "root_cause_files": ["rich/cells.py", "rich/segment.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "pyproject.toml"]}, "id": "856ebfc3039957f7713cc7d4", "metadata": {"confidence": "weak", "created_at": "2024-10-22T14:45:17Z", "evidence": {"implementation_files": ["rich/cells.py", "rich/segment.py"], "related_tests": ["tests/test_cells.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2024-10-22T15:34:56Z", "pr": 3535, "pr_url": "https://github.com/Textualize/rich/pull/3535"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 5 total files.", "implementation_file_count": 2, "implementation_files": ["rich/cells.py", "rich/segment.py"], "pr_body": "Fixes an issue with the regex used to select the fast path for strings with single-width characters.\n\nThis may have had a detrimental effect on performance for some operations.", "pr_title": "Regex error"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "9bf344f760e7644c2ecf6b6d2c9748b1c425611a", "candidate_corpus": {"base_commit": "9bf344f760e7644c2ecf6b6d2c9748b1c425611a", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "ad608014d95691abbad3904a7a9501ca66729ff1", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/bin/bat/app.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "d9931d3ebeccb02da2dda422", "metadata": {"confidence": "weak", "created_at": "2025-12-19T09:42:40Z", "evidence": {"implementation_files": ["src/bin/bat/app.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2025-12-23T17:08:38Z", "pr": 3529, "pr_url": "https://github.com/sharkdp/bat/pull/3529"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/bin/bat/app.rs"], "pr_body": "# Description\nThis change resolves the request made in issue #3526. \nI added a condition to an if statement in the file \"*src/bin/bat/app.rs*\". \nTo test the fix, you can run the command:\n```\ncargo run -- FILENAME --terminal-width SIZE -p\n```", "pr_title": "fix issue #3526"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "66074922edabeac684434b4d87ee994fb97b0627", "candidate_corpus": {"base_commit": "66074922edabeac684434b4d87ee994fb97b0627", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "0f2f51b872d14588de3a65968f5cdde6fb5694a3", "negative_distractors": [], "related_tests": ["tests/test_segment.py"], "root_cause_files": ["rich/segment.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "pyproject.toml"]}, "id": "dad00a18db2aeab4062f58d3", "metadata": {"confidence": "weak", "created_at": "2024-10-04T11:45:26Z", "evidence": {"implementation_files": ["rich/segment.py"], "related_tests": ["tests/test_segment.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2024-10-04T11:49:13Z", "pr": 3521, "pr_url": "https://github.com/Textualize/rich/pull/3521"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 1, "implementation_files": ["rich/segment.py"], "pr_body": "Fixes https://github.com/Textualize/textual/issues/5090", "pr_title": "Segment.split_cells fix"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "5ba9cb56e68dcdf2db50c214d8f1412c8a50761b", "candidate_corpus": {"base_commit": "5ba9cb56e68dcdf2db50c214d8f1412c8a50761b", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "66074922edabeac684434b4d87ee994fb97b0627", "negative_distractors": [], "related_tests": ["tests/test_table.py"], "root_cause_files": ["rich/table.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "f7eb9f4fd75cfb3a15892a4d", "metadata": {"confidence": "weak", "created_at": "2024-10-03T15:10:54Z", "evidence": {"implementation_files": ["rich/table.py"], "related_tests": ["tests/test_table.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2024-10-04T09:40:50Z", "pr": 3518, "pr_url": "https://github.com/Textualize/rich/pull/3518"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["rich/table.py"], "pr_body": "## Type of changes\n\n- [x] Bug fix\n- [ ] New feature\n- [ ] Documentation / docstrings\n- [ ] Tests\n- [ ] Other\n\n## Checklist\n\n- [x] I've run the latest [black](https://github.com/psf/black) with default args on new code.\n- [x] I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate.\n- [x] I've added tests for new code.\n- [x] I accept that @willmcgugan may be pedantic in the code review.\n\n## Description\n\nFixes #3517. The default value for the `Column.highlight` is False, so where necessary columns are added by the `add_row` method this should default to the `Table.highlight` value.", "pr_title": "fix(table): highlight columns added by add_row"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "eb2a8e29c7681d1e371ff8eda4512e7c101c2a2d", "candidate_corpus": {"base_commit": "eb2a8e29c7681d1e371ff8eda4512e7c101c2a2d", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "9bf344f760e7644c2ecf6b6d2c9748b1c425611a", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/preprocessor.rs", "src/printer.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "README.md", "tests/examples/git-commit.man", "tests/examples/overstrike.txt"]}, "id": "61f86746c49f84b63fdef563", "metadata": {"confidence": "weak", "created_at": "2025-12-05T13:29:37Z", "evidence": {"implementation_files": ["src/preprocessor.rs", "src/printer.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2025-12-11T06:36:18Z", "pr": 3517, "pr_url": "https://github.com/sharkdp/bat/pull/3517"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 7 total files.", "implementation_file_count": 2, "implementation_files": ["src/preprocessor.rs", "src/printer.rs"], "pr_body": "Potentially fixes #652, #2479, #2568, #3025, #3053\n\nI noticed that running `git commit --help | bat -plhelp` displayed text with visible `^H` characters and doubled letters. I realized that this happens because man pages use something called overstriking where (similar to a typewriter) a character is typed twice over each other. `bat` was styling the page and passing through the `^H` which lead to this mixed output.\n\n\"Screenshot\n\nSo as a solution I introduced a `strip_overstrike()` function to simply remove the backspace formatting to allow syntax highlighters to modify the output undisturbed and applies this stripping in both `SimplePrinter` and `InteractivePrinter`. `Cow` is used to avoid allocation when no backspaces are present. \n\nI am not an overly heavy user of `bat` but in my testing of this fix, I tried to verify that:\n- Now `MANPAGER=\"bat -p -l man\" man ls` displays cleanly.\n- `git commit --help | bat -plhelp` now works correctly.\n- `--binary=as-text` still preserves raw bytes.\n\nI am not sure if there are other scenarios that I missed where stripping the overstriking might be unintentional.\n\nAfter all, the above renders like this with this patch:\n\n\"Screenshot\n\nOn as side note: I realized that `git commit --help | bat -plhelp` displays the text not full-width but this is coming from `git commit --help` when it detects that its output is being piped. One workaround is to run `MANWIDTH=$(tput cols) git commit --help | bat -plhelp`", "pr_title": "Improve native man pages and command help syntax highlighting by stripping overstriking"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "7022e202245b6bdeb39e8025d2b5dab793841ec8", "candidate_corpus": {"base_commit": "7022e202245b6bdeb39e8025d2b5dab793841ec8", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "92abd703b34cc8cdcd581b5128ad5eab89a9c9e5", "negative_distractors": ["rich/padding.py", "rich/panel.py", "rich/progress.py", "rich/segment.py", "rich/text.py"], "related_tests": ["tests/test_panel.py", "tests/test_progress.py"], "root_cause_files": ["rich/_null_file.py", "rich/_win32_console.py", "rich/console.py", "rich/padding.py", "rich/panel.py", "rich/progress.py", "rich/segment.py", "rich/text.py"], "root_cause_symbols": [], "supporting_files": [".github/workflows/codespell.yml", "CHANGELOG.md", "poetry.lock", "pyproject.toml"]}, "id": "0b196fe47691c1fb816fdd34", "metadata": {"confidence": "weak", "created_at": "2024-09-30T18:49:33Z", "evidence": {"implementation_files": ["rich/_null_file.py", "rich/_win32_console.py", "rich/console.py", "rich/padding.py", "rich/panel.py", "rich/progress.py", "rich/segment.py", "rich/text.py"], "related_tests": ["tests/test_panel.py", "tests/test_progress.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2024-10-01T12:08:20Z", "pr": 3509, "pr_url": "https://github.com/Textualize/rich/pull/3509"}, "query": {"changed_file_summary": "8 implementation files and 2 existing test files changed within 14 total files.", "implementation_file_count": 8, "implementation_files": ["rich/_null_file.py", "rich/_win32_console.py", "rich/console.py", "rich/padding.py", "rich/panel.py", "rich/progress.py", "rich/segment.py", "rich/text.py"], "pr_body": "Fixes https://github.com/Textualize/rich/issues/3493\n\nDrops Python3.7 support\n\nBumps to v 13.9.0", "pr_title": "respect text.style in panels"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "c74ca27075ffefda45036bee3ddb039379967847", "candidate_corpus": {"base_commit": "c74ca27075ffefda45036bee3ddb039379967847", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "6dfe471686e080755139ce4ce08500b3d25de1a2", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/bin/bat/app.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "ee924fd54cb8f19db8904b87", "metadata": {"confidence": "weak", "created_at": "2025-12-01T03:30:49Z", "evidence": {"implementation_files": ["src/bin/bat/app.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2025-12-01T19:36:58Z", "pr": 3507, "pr_url": "https://github.com/sharkdp/bat/pull/3507"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["src/bin/bat/app.rs"], "pr_body": "While still ignoring ignoring invalid arguments in the config", "pr_title": "Ensure --help respects valid config file"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "4101991898ee7a09fe1706daca24af5e1e054862", "candidate_corpus": {"base_commit": "4101991898ee7a09fe1706daca24af5e1e054862", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "d5dcc74d0255d3dbcbb9f0bba208bdde2e40ec54", "negative_distractors": [], "related_tests": ["tests/test_segment.py"], "root_cause_files": ["rich/segment.py"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md"]}, "id": "ef65a74ab10f4ba44f30760f", "metadata": {"confidence": "weak", "created_at": "2024-09-28T19:19:50Z", "evidence": {"implementation_files": ["rich/segment.py"], "related_tests": ["tests/test_segment.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2024-09-28T19:39:32Z", "pr": 3506, "pr_url": "https://github.com/Textualize/rich/pull/3506"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["rich/segment.py"], "pr_body": "Fixed `Segment._split_cells` issue discovered in https://github.com/Textualize/textual/issues/4996", "pr_title": "fix split cells"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "d17481575a0f6e84073c14947def04284518ecae", "candidate_corpus": {"base_commit": "d17481575a0f6e84073c14947def04284518ecae", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "1ffed0c039f7a7d329950dac0b60cc848ccd49a7", "negative_distractors": [], "related_tests": ["tests/integration_tests.rs"], "root_cause_files": ["src/bin/bat/app.rs"], "root_cause_symbols": [], "supporting_files": ["CHANGELOG.md", "README.md"]}, "id": "c9c09a5afa5e77c372fec2a1", "metadata": {"confidence": "weak", "created_at": "2025-11-27T20:27:42Z", "evidence": {"implementation_files": ["src/bin/bat/app.rs"], "related_tests": ["tests/integration_tests.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2025-11-30T03:14:01Z", "pr": 3496, "pr_url": "https://github.com/sharkdp/bat/pull/3496"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 1, "implementation_files": ["src/bin/bat/app.rs"], "pr_body": "Fixes #3487", "pr_title": "Restore expected behavior when piping output with styles configured and auto decorations"}, "query_provenance": "pr_summary", "repo": "sharkdp/bat", "task_type": "code2test", "version": 2} +{"base_commit": "d0de442c08df8793c5ff36d9ad322ca5c47fc38c", "candidate_corpus": {"base_commit": "d0de442c08df8793c5ff36d9ad322ca5c47fc38c", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "4101991898ee7a09fe1706daca24af5e1e054862", "negative_distractors": [], "related_tests": ["tests/test_traceback.py"], "root_cause_files": ["rich/default_styles.py", "rich/syntax.py", "rich/traceback.py"], "root_cause_symbols": [], "supporting_files": [".github/workflows/pythonpackage.yml", "CHANGELOG.md", "poetry.lock", "pyproject.toml"]}, "id": "7880c2badfd19f6a327a204b", "metadata": {"confidence": "weak", "created_at": "2024-09-10T15:22:23Z", "evidence": {"implementation_files": ["rich/default_styles.py", "rich/syntax.py", "rich/traceback.py"], "related_tests": ["tests/test_traceback.py"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2024-09-11T10:29:27Z", "pr": 3486, "pr_url": "https://github.com/Textualize/rich/pull/3486"}, "query": {"changed_file_summary": "3 implementation files and 1 existing test files changed within 8 total files.", "implementation_file_count": 3, "implementation_files": ["rich/default_styles.py", "rich/syntax.py", "rich/traceback.py"], "pr_body": "Adds PEP 657 finely grained error locations to rich.traceback", "pr_title": "report fine grained error locations"}, "query_provenance": "pr_summary", "repo": "Textualize/rich", "task_type": "code2test", "version": 2} +{"base_commit": "10734681632b9fdebba1650a18d75dfebf678909", "candidate_corpus": {"base_commit": "10734681632b9fdebba1650a18d75dfebf678909", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "ab593bbab7e0e3203d8e15e09208f3cd8bd43fb4", "negative_distractors": [], "related_tests": ["axum/src/routing/tests/fallback.rs"], "root_cause_files": ["axum/src/routing/route.rs"], "root_cause_symbols": [], "supporting_files": ["axum/src/docs/method_routing/fallback.md"]}, "id": "9db4bce0e6ada5316da78331", "metadata": {"confidence": "weak", "created_at": "2025-09-12T07:47:09Z", "evidence": {"implementation_files": ["axum/src/routing/route.rs"], "related_tests": ["axum/src/routing/tests/fallback.rs"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2025-09-16T08:29:02Z", "pr": 3465, "pr_url": "https://github.com/tokio-rs/axum/pull/3465"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["axum/src/routing/route.rs"], "pr_body": "Related: [#3464](https://github.com/tokio-rs/axum/pull/3464)\n\n\n\n## Motivation\n\nSome applications configure method_not_allowed_fallback specifically to return 404 for unimplemented HTTP methods and to avoid revealing which methods are supported. Today, MethodRouter still injects an Allow header even when a method_not_allowed_fallback is present, which leaks the set of supported methods and undermines this use case. Removing the header in middleware is brittle and adds overhead, and introducing a per-route “skip allow” knob would require touching every route. Per RFC 9110, Allow is required on 405 responses but not on 404, so omitting it when a 404 fallback is used is compliant.\n\n\n\n## Solution\n\n\n\nWhen a MethodRouter has a method_not_allowed_fallback configured, do not automatically insert the Allow header. \nIn this mode the fallback is considered authoritative and can set status and headers as it sees fit (including explicitly sending 405 + Allow if desired). \nThe default behavior is unchanged: without a fallback, MethodRouter continues to respond with 405 and includes the Allow header. This avoids information leakage for internal/undocumented APIs while preserving RFC-compliant behavior by default.", "pr_title": "routing: omit Allow header when method_not_allowed_fallback is config…"}, "query_provenance": "pr_summary", "repo": "tokio-rs/axum", "task_type": "code2test", "version": 2} +{"base_commit": "40c22f4bc57d4ea6aa323928c037c947890fe81c", "candidate_corpus": {"base_commit": "40c22f4bc57d4ea6aa323928c037c947890fe81c", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "296824015d4a6345531fa71e9233fd42879f2c69", "negative_distractors": [], "related_tests": ["router_test.go"], "root_cause_files": ["router.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "a65621c74d86d052d977148a", "metadata": {"confidence": "weak", "created_at": "2026-10-05T23:10:00Z", "evidence": {"implementation_files": ["router.go"], "related_tests": ["router_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-06T03:26:19Z", "pr": 3160, "pr_url": "https://github.com/labstack/echo/pull/3160"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["router.go"], "pr_body": "`Router.Remove` panics with a nil pointer dereference for a route registered with a custom method, for example `e.Add(\"PURGE\", \"/cache\", h)` followed by `e.Router().Remove(\"PURGE\", \"/cache\")`. `ConcurrentRouter.Remove` delegates to it, so it panics too.\n\n**Cause:** `Remove` clears the handler with `setHandler(method, nil)`. Methods with their own field (GET, POST, …) just set it to nil. Custom methods fall through to the `default` branch of `routeMethods.set`, which read `r.handler` on the nil route.\n\n**Fix:** treat a nil route like a nil handler and delete the `anyOther` entry. `Remove` is the only caller that passes nil.\n\n**Test:** `TestDefaultRouter_RemoveCustomMethod` covers two cases:\n- Removing a custom-method route from a path that keeps its GET route: the Routes list is updated, a later PURGE request gets 405, and PURGE is gone from the Allow header.\n- Removing the only route on a path: a later request gets 404.\n\nIt panics on master and passes here. `go test -race ./...`, `go vet`, `staticcheck` and `golint` pass.\n\nv4 has no `Router.Remove`, so this is v5 only.", "pr_title": "fix(router): removing a route with a custom method panics"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "320fe67b1e4eae941cec6b185eddd07a2ac4765b", "candidate_corpus": {"base_commit": "320fe67b1e4eae941cec6b185eddd07a2ac4765b", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "be0800562a0b6760d570b19fc372c3aa3c378978", "negative_distractors": [], "related_tests": ["echo_test.go", "router_test.go"], "root_cause_files": ["router.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "2c72af3c05e5eecb9f34fe7a", "metadata": {"confidence": "weak", "created_at": "2026-10-05T22:10:34Z", "evidence": {"implementation_files": ["router.go"], "related_tests": ["echo_test.go", "router_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-06T02:52:15Z", "pr": 3158, "pr_url": "https://github.com/labstack/echo/pull/3158"}, "query": {"changed_file_summary": "1 implementation files and 2 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["router.go"], "pr_body": "Adding a route with path params after Echo has served requests can panic with `index out of range [0] with length 0`. It happens in sequential, single-goroutine use:\n- A late **any** route (`/files/*`) panics in every v4 release: in `Router.Find`, or already in `Context.Reset` from v4.1.12 to v4.11.x.\n- A late **param** route (`/users/:id`) wrongly returned 404 up to v4.1.11. From v4.1.12 to v4.11.x it panics in `Context.Reset`, on the next request of any kind.\n- From v4.12.0 (after #2611), late param and any routes panic in `Router.Find`, on requests whose routing reaches the late param or any node. That includes some 404s and 405s.\n\n**Repro:** register `GET /static`, serve `/static`, register `GET /users/:id`, serve `/users/42`.\n\n**Cause:** pooled contexts keep the `pvalues` length they were created with (`*e.maxParam` at the time), and `Router.Find` sets values by index. #2611 fixed `SetParamNames`/`SetParamValues` and `Reset`, but not `Find`.\n\n**Fix:** when `Find` is about to set a param or any value past the context's `pvalues` length, it grows the slice to `*r.echo.maxParam`, keeps the values already set, and stores it on the context. Static routes never reach these branches.\n\nThis does not make it safe to add routes concurrently with serving. That is still unsupported in v4, as discussed in #1705.\n\n**Cost:** 20 interleaved rounds against v4 show +0.9% geomean on router benchmarks, with 0 allocs. Static routes are unchanged. Param-heavy routes rise up to about +2.8%, which is about 0.5–1.4 ns per param lookup. This was the cheapest of three placements measured (top of `Find`: +1.1%; `Reset` with `clear()`: +2.6%).\n\n**Tests:**\n- `TestEchoAddParamRouteAfterServing` is the end-to-end repro.\n- `TestRouterFindWithContextCreatedBeforeParamRouteAdded` covers a param rout\n...[truncated]", "pr_title": "fix(router): grow param values for contexts created before a route with more params (v4)"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "40c22f4bc57d4ea6aa323928c037c947890fe81c", "candidate_corpus": {"base_commit": "40c22f4bc57d4ea6aa323928c037c947890fe81c", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "4f7bea5d2ad253d2d0fddb1382ae25be040a3d8b", "negative_distractors": [], "related_tests": ["echo_test.go", "router_test.go"], "root_cause_files": ["router.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "56b8efca3bbc05709ba85dc4", "metadata": {"confidence": "weak", "created_at": "2026-10-05T22:10:31Z", "evidence": {"implementation_files": ["router.go"], "related_tests": ["echo_test.go", "router_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-06T02:52:10Z", "pr": 3157, "pr_url": "https://github.com/labstack/echo/pull/3157"}, "query": {"changed_file_summary": "1 implementation files and 2 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["router.go"], "pr_body": "Adding a route with more path params after Echo has served requests panics with `index out of range [0] with length 0` on the next request that matches it. This happens with both `DefaultRouter` and `ConcurrentRouter`, even though `NewConcurrentRouter` says routes can be added after the server has started. The faulty line is in every v5 release (v5.0.0 through v5.4.0).\n\n**Repro:** register `GET /static`, serve `/static`, register `GET /users/:id`, serve `/users/42`.\n\n**Cause:** pooled `Context`s keep the `PathValues` capacity they were created with. `DefaultRouter.Route` already detected the short capacity, but it allocated a zero-length slice (`make(PathValues, 0, max)`) and then set values by index. The same branch is reached by Contexts created without an Echo and when routes are added through `Router().Add` directly; both panic on master too.\n\n**Fix:** grow the Context's `PathValues` at full length in that existing branch. The Context keeps the new slice, so it is grown once, whatever route the request matches (static, param, 404 or 405), until a route with even more params is added. The `Router` contract comment now says that `Route` must handle a Context with a smaller capacity, and that adding routes through Echo is what keeps Contexts sized up front.\n\n**Cost:** the change only touches the branch that already handled short capacity, so steady state is unchanged:\n- `ServeHTTP_*`, `Echo*API` and `Router*API` benchmarks: 20 interleaved rounds against master show no regression, and allocations per operation are unchanged.\n- After its first request, a stale Context allocates the same as a fresh one for static, 404, 405 and param routes. On master, when routes have 2 or more params, a stale Context serving static or 404 requests allocated one slice per request indefini\n...[truncated]", "pr_title": "fix(router): grow PathValues for contexts created before a route with more params"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "f085ffbe8f99de165bd920746920000ab56bd6bc", "candidate_corpus": {"base_commit": "f085ffbe8f99de165bd920746920000ab56bd6bc", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "320fe67b1e4eae941cec6b185eddd07a2ac4765b", "negative_distractors": [], "related_tests": ["bind_test.go"], "root_cause_files": ["bind.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "6d4e5fba04cfba72e2c78af4", "metadata": {"confidence": "weak", "created_at": "2026-10-05T18:21:59Z", "evidence": {"implementation_files": ["bind.go"], "related_tests": ["bind_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-05T19:22:05Z", "pr": 3156, "pr_url": "https://github.com/labstack/echo/pull/3156"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["bind.go"], "pr_body": "Backport of #3145 to v4.\n\nSwag and OpenAPI put format names such as `format:\"date-time\"` on `time.Time` fields. Since v4.14.0 added `format` tag support, the binder has treated those names as Go time layouts, so valid input failed to bind. Before v4.14.0 the tag was ignored, so RFC3339 values bound to swag-annotated `format:\"date-time\"` fields. That case broke on upgrade.\n\n- `date-time` uses the same RFC3339 decoding as an untagged `time.Time`, which restores the pre-v4.14.0 behavior.\n- `date-time-local` accepts `2006-01-02T15:04:05` with optional fractional seconds, rejects time-zone suffixes, and assigns UTC.\n- `date` accepts `2006-01-02` and assigns UTC.\n- For `date-time-local` and `date`, zoned RFC3339 values bound before v4.14.0 only because the tag was ignored. They stay rejected, as the OpenAPI definitions require.\n- Parsing uses Go's `time` package, so it is as lenient as untagged `time.Time` binding (for example, it accepts a comma before fractional seconds).\n- Other `format` values are still Go layouts. Slice fields never used the tag and are unchanged.\n\nCompared with current v4, the only inputs that bound before and now fail are the literal strings `date-time`, `date-time-local`, and `date`, which parsed to `0000-01-01T00:00:00Z`.\n\nThe tests are ported from #3145 and adapted to the v4 binder API. They cover path, query, header, form, and multipart sources, scalar and pointer fields, JSON decoding, custom types, the literal format names, and slice fields. Without the fix, 53 of the new cases fail. With it, `go test -race ./...`, `staticcheck`, and `golint` pass.\n\nThe `BindPathParams` doc now mentions the OpenAPI names and headers, and its HTML `datetime-local` example uses a `form` tag. Two existing lines in `TestTimeFormatBinding` are gofmt-aligned.\n\nRefs #31\n...[truncated]", "pr_title": "fix(bind): honor OpenAPI date, date-time and date-time-local format tags (v4)"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "99c395d846e079d4cffd29de9298d1dd829e8b04", "candidate_corpus": {"base_commit": "99c395d846e079d4cffd29de9298d1dd829e8b04", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "8fd0e184dd390ffdf082f5eda247c3ab41d5d290", "negative_distractors": [], "related_tests": ["context_test.go"], "root_cause_files": ["context.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "7a1094b96c910317406b8a8f", "metadata": {"confidence": "weak", "created_at": "2026-10-04T13:21:14Z", "evidence": {"implementation_files": ["context.go"], "related_tests": ["context_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-12T15:06:45Z", "pr": 3152, "pr_url": "https://github.com/labstack/echo/pull/3152"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["context.go"], "pr_body": "This adds c.ValidateCtx(v) to pass the request context to the validator, as discussed in [#2399](https://github.com/labstack/echo/discussions/2399). If the validator doesn't implement ValidateCtx, it calls Validate instead.\n\nI left c.Validate(v) unchanged. Making it call ValidateCtx automatically could skip a wrapper's own validation when it embeds another validator with that method.", "pr_title": "feat(context): add ValidateCtx"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "99c395d846e079d4cffd29de9298d1dd829e8b04", "candidate_corpus": {"base_commit": "99c395d846e079d4cffd29de9298d1dd829e8b04", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "bbc6de8ac782ea57c17de2dce22d7c31fb74ffea", "negative_distractors": [], "related_tests": ["bind_test.go"], "root_cause_files": ["bind.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "e0c59a2314376de2533be339", "metadata": {"confidence": "weak", "created_at": "2026-10-02T18:00:16Z", "evidence": {"implementation_files": ["bind.go"], "related_tests": ["bind_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-10-05T19:10:08Z", "pr": 3145, "pr_url": "https://github.com/labstack/echo/pull/3145"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["bind.go"], "pr_body": "Adding a swag `format:\"date-time\"` tag to a `time.Time` field made Echo read the OpenAPI format name as a Go time layout, which rejected valid RFC3339 input.\n\nThis change recognizes three OpenAPI format names for `time.Time` and `*time.Time` fields in path, query, header, and form binding:\n\n- `date-time` uses the same standard-library text decoder as an untagged `time.Time`. It accepts RFC3339 timestamps with `Z` or a numeric offset.\n- `date-time-local` accepts `2006-01-02T15:04:05` with optional fractional seconds and rejects time-zone suffixes.\n- `date` accepts `2006-01-02`.\n\nParsing uses Go's `time` package, so it is as lenient as untagged `time.Time` binding (for example, it accepts a comma before fractional seconds). `date` and `date-time-local` give UTC times, as custom layouts without a time zone already do. That is Echo's parsing policy; the input itself does not specify UTC. The formats have distinct meanings in the [OpenAPI registry](https://spec.openapis.org/registry/format/). Other format values are still Go layouts. JSON/XML decoding, custom unmarshalers, and slice fields (which never used the format tag) are unchanged. The `DefaultBinder` doc also points HTML `datetime-local` inputs, which omit seconds by default, to a Go layout such as `2006-01-02T15:04`.\n\nCompared with master, the only inputs that bound before and now fail are the literal strings `date-time`, `date-time-local`, and `date`, which parsed to `0000-01-01T00:00:00Z`.\n\nValidation:\n\n- `go test -race ./...`, `go vet ./...`, `staticcheck ./...`, `golint -set_exit_status ./...`\n- The regression cases cover all three formats, scalar and pointer fields, all five binding sources, fractional seconds, preserved offsets, invalid dates, missing and forbidden time zones, JSON decoding, custom types, the l\n...[truncated]", "pr_title": "fix(bind): honor OpenAPI date, date-time and date-time-local format tags"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "5440f99719cc8de4be2ae6abfc8f275302791730", "candidate_corpus": {"base_commit": "5440f99719cc8de4be2ae6abfc8f275302791730", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "f085ffbe8f99de165bd920746920000ab56bd6bc", "negative_distractors": [], "related_tests": ["router_test.go"], "root_cause_files": ["route_path.go", "router.go"], "root_cause_symbols": [], "supporting_files": ["route_syntax_test.go"]}, "id": "5f4ff2ce3c8ec04d32ec0453", "metadata": {"confidence": "weak", "created_at": "2026-09-29T20:28:04Z", "evidence": {"implementation_files": ["route_path.go", "router.go"], "related_tests": ["router_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-30T01:00:17Z", "pr": 3132, "pr_url": "https://github.com/labstack/echo/pull/3132"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["route_path.go", "router.go"], "pr_body": "## Summary\n\nBackports the escaped-colon router fix in #3113 and the inline-verb follow-up in #3133 to v4. Routes with escaped literal colons and parameter routes stay reachable in either registration order, including paths with encoded NUL bytes.\n\n- **One route-syntax scanner** for registration and reverse routing. An escaped colon after a parameter starts an inline verb (`/:name\\:cancel`) when the rest of that path segment is static. Other escaped colons after a parameter keep their older meaning as part of the parameter name.\n- **Inline verb matching** works as in #3133. A failed split is retried on the same param node, with the next split and finally the whole segment, before routing backtracks to its parent. Static > param > any priority, group middleware and catch-all routes are unaffected by a failed split, and a failed wildcard below a split keeps backtracking.\n- **Linear time:** O(path length × longest registered verb).\n- **Leaf params keep working.** When the inline verb child is a param node's only child, a value without a split still takes the rest of the path.\n- **`ParamNames()`** stays a non-nil empty slice for static routes. `Reverse` placeholders drop the backslash of escaped colons, as before.\n\nv4 has no route removal API, so the removal fix in #3133 applies only to v5.\n\n## Compatibility notes (release notes)\n\n- `/x/:id\\:y` now registers parameter `id` and a literal `:y`. Before, it registered one parameter named `id\\:y` that matched any segment. This is the fix for #3111; apps that relied on the old reading of such routes see different params and matching.\n- A matching inline verb split is preferred over the whole segment, also when the verb is followed by a wildcard.\n\n## Performance\n\nRouter benchmarks against v4, 8 interleaved runs on Apple M3 Max: geo\n...[truncated]", "pr_title": "fix(router): handle escaped colons and inline verbs in v4"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "577ba391f2374cd304a0548ce40fe43708a23fc4", "candidate_corpus": {"base_commit": "577ba391f2374cd304a0548ce40fe43708a23fc4", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "5440f99719cc8de4be2ae6abfc8f275302791730", "negative_distractors": [], "related_tests": ["middleware/body_limit_test.go"], "root_cause_files": ["bind.go", "middleware/body_limit.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "f9dfdafe1ee292b57f9cb58b", "metadata": {"confidence": "weak", "created_at": "2026-09-29T19:48:40Z", "evidence": {"implementation_files": ["bind.go", "middleware/body_limit.go"], "related_tests": ["middleware/body_limit_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-29T20:10:24Z", "pr": 3131, "pr_url": "https://github.com/labstack/echo/pull/3131"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 2, "implementation_files": ["bind.go", "middleware/body_limit.go"], "pr_body": "## Summary\n\nBackports the BodyLimit fix from #3087 to v4. Requests without a known Content-Length could previously expose bytes beyond the configured limit to handlers; single large reads could return the whole body with a 413 error, and repeated small reads could expose one extra byte.\n\n- Cap each underlying read to the remaining allowance plus one probe byte, and return only allowed bytes. Keep the 413 error on subsequent reads.\n- Give each request its own reader so `Request.Body` remains valid after the middleware handler returns.\n- Preserve 413 through XML, form, and multipart binding; v4's JSON binder already preserves it.\n- Reject negative configured limits.\n\nThe reader retains v4's existing zero-limit behavior. As with the v5 fix, the custom reader does not signal `net/http` to close the connection after a limit error as `http.MaxBytesReader` would.\n\n## Verification\n\n- `go test ./... -count=1`\n- `go vet ./...`\n- `go test -race ./middleware -run TestBodyLimit -count=1`\n- Regression tests cover large and one-byte reads, exact boundaries, `math.MaxInt64`, ordinary read errors, reader lifetime, and JSON/XML/form/multipart binding with unknown Content-Length.\n\nRefs #3071 (v4 backport of #3087; the issue closes with the v5 fix)", "pr_title": "fix(middleware): prevent BodyLimit bypass in v4"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "573044517968cd3cfe901cff8f75bc807dee874b", "candidate_corpus": {"base_commit": "573044517968cd3cfe901cff8f75bc807dee874b", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "577ba391f2374cd304a0548ce40fe43708a23fc4", "negative_distractors": [], "related_tests": ["echo_fs_test.go", "middleware/static_test.go"], "root_cause_files": ["echo_fs.go", "middleware/static.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "9f8a5699a2ba5d64fd16e5b1", "metadata": {"confidence": "weak", "created_at": "2026-09-29T17:50:41Z", "evidence": {"implementation_files": ["echo_fs.go", "middleware/static.go"], "related_tests": ["echo_fs_test.go", "middleware/static_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-29T18:17:12Z", "pr": 3130, "pr_url": "https://github.com/labstack/echo/pull/3130"}, "query": {"changed_file_summary": "2 implementation files and 2 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["echo_fs.go", "middleware/static.go"], "pr_body": "Backport of #3129 to v4.\n\n- **Hardening:** the dot-segment check (`hasDotOrEmptySegment`, in `echo_fs.go` and `middleware/static.go`) now also rejects `.` and `..` parts separated by a backslash (e.g. `..\\secret.txt`). Such a name reaches the filesystem with the default configuration via `/..%5Csecret.txt` or a literal backslash, and via `/..%5csecret.txt` when path unescaping is enabled. A backslash is a literal character in `fs.FS` names, and `os.DirFS`, `embed.FS` and Echo's default filesystem are not affected; but a custom filesystem that wrongly treats a backslash as a separator (such as one built on `filepath.Join` on Windows) would otherwise resolve it outside its root. Names containing a backslash but no `.`/`..` part are unaffected.\n- **Regression tests** with a non-validating filesystem that treats backslash as a separator on every OS, for `Echo.StaticFS` (with and without `EnablePathUnescapingStaticFiles`) and the static middleware via `http.FS` (root and group routes, with and without `EnablePathUnescaping`), covering literal `..`, `%2e%2e`, `..%2f`, nested `..`, `..%5c`, `..%5C`, `a%5C..%5C..` and literal `..\\`; plus unit tests for the helper. The tests fail without the change on every OS.\n- **Comments:** the helper doc and the path-handling comment in `middleware/static.go` now describe the backslash rule.\n\nChangelog: `static: do not open paths with a \".\" or \"..\" part between backslashes (hardening for custom filesystems that treat a backslash as a separator)`.", "pr_title": "static: harden dot-segment check for backslashes, test non-validating custom fs.FS (v4)"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "ba97b3f4a978f855b5b4a9c66cc69ea7e6fdb4d2", "candidate_corpus": {"base_commit": "ba97b3f4a978f855b5b4a9c66cc69ea7e6fdb4d2", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "bc4028f1d7cc373823de8b6eb057cd4a9d5fc85c", "negative_distractors": [], "related_tests": ["echo_test.go", "middleware/static_test.go"], "root_cause_files": ["echo.go", "middleware/static.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "e9f939b082f91b7447ae6d77", "metadata": {"confidence": "weak", "created_at": "2026-09-29T17:38:27Z", "evidence": {"implementation_files": ["echo.go", "middleware/static.go"], "related_tests": ["echo_test.go", "middleware/static_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-29T18:17:06Z", "pr": 3129, "pr_url": "https://github.com/labstack/echo/pull/3129"}, "query": {"changed_file_summary": "2 implementation files and 2 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["echo.go", "middleware/static.go"], "pr_body": "A custom `fs.FS` that does not follow the `fs.FS` contract (for example a hand-written adapter over a directory or object store that joins names with `filepath.Join`) could resolve a requested name outside its root. Since v5.4.0 (GHSA-3pmx-cf9f-34xr) Echo does not open paths with a `.`, `..` or empty segment, so a name with a `..` element is never passed to `Open`.\n\nChanges:\n\n- **Hardening:** the dot-segment check now also rejects `.` and `..` parts separated by a backslash (e.g. `..\\secret.txt`). Such a name reaches the filesystem with the default configuration via `/..%5Csecret.txt` or a literal backslash, and via `/..%5csecret.txt` when path unescaping is enabled. A backslash is a literal character in `fs.FS` names, and `os.DirFS`, `embed.FS` and Echo's default filesystem are not affected; but a custom filesystem that wrongly treats a backslash as a separator (such as one built on `filepath.Join` on Windows) would otherwise resolve it outside its root. Names containing a backslash but no `.`/`..` part (e.g. `dir\\file.txt`) are unaffected.\n- **Regression tests** with a non-validating filesystem that treats backslash as a separator on every OS, for `Echo.StaticFS` (with and without `EnablePathUnescapingStaticFiles`) and the static middleware (root and group routes, with and without `EnablePathUnescaping`), covering literal `..`, `%2e%2e`, `..%2f`, nested `..`, `..%5c`, `..%5C`, `a%5C..%5C..` and literal `..\\`; plus unit tests for the helper. The tests fail without the change on Linux, macOS and Windows.\n- **Comments:** `middleware/static.go` said the `\"/\"` prefix removes `..` components (the code uses `\"./\"`; `..` paths are not opened and are handled like a missing file) and referenced a non-existent `static_windows.go`; the helper doc now describes the backslash rule.\n...[truncated]", "pr_title": "static: harden dot-segment check for backslashes, test non-validating custom fs.FS"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "3d084be9022432c5a5257924c7d74bfc3444b456", "candidate_corpus": {"base_commit": "3d084be9022432c5a5257924c7d74bfc3444b456", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "eadbef28df3b293a7e7b39977ac949c5907fa559", "negative_distractors": [], "related_tests": ["router_test.go"], "root_cause_files": ["router.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "dcd90eb2e128966ee9815802", "metadata": {"confidence": "weak", "created_at": "2026-09-22T16:26:32Z", "evidence": {"implementation_files": ["router.go"], "related_tests": ["router_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-29T20:28:31Z", "pr": 3113, "pr_url": "https://github.com/labstack/echo/pull/3113"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["router.go"], "pr_body": "Refs #3111\n\nA route with a literal colon (written as `\\:`) and a parameter route at the same tree position used the same `:` marker during insertion. Depending on registration order, `ServeHTTP` could panic or a route could become unreachable.\n\nTrack parameter-marker positions during insertion so a literal colon remains a static path byte. This also avoids reserving another byte that could collide with a valid route path.\n\nTests cover both registration orders through the router and through `ServeHTTP`, including an encoded NUL route that the earlier placeholder approach would have broken.\n\nThe v4 backport will close #3111 after both versions are fixed.", "pr_title": "fix(router): keep escaped colon and parameter routes reachable"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "90702e71a7cde342da70b1f97e8e6420c509f939", "candidate_corpus": {"base_commit": "90702e71a7cde342da70b1f97e8e6420c509f939", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "df5edd9146e40342726d71cbb71300b7fea096d0", "negative_distractors": [], "related_tests": ["rfc9457_test.go"], "root_cause_files": ["rfc9457.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "c82b9e64ccd6377386e55f70", "metadata": {"confidence": "weak", "created_at": "2026-09-11T01:36:46Z", "evidence": {"implementation_files": ["rfc9457.go"], "related_tests": ["rfc9457_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-11T05:12:32Z", "pr": 3094, "pr_url": "https://github.com/labstack/echo/pull/3094"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["rfc9457.go"], "pr_body": "## Problem\n\n`ProblemDetailsHTTPErrorHandler` fills in the zero-valued `Type`, `Title` and `Status` fields by writing them back into the `*ProblemError` it was handed:\n\n```go\nif pe.Status == 0 {\n pe.Status = http.StatusInternalServerError\n}\nif pe.Type == \"\" {\n pe.Type = \"about:blank\"\n}\nif pe.Title == \"\" {\n pe.Title = http.StatusText(pe.Status)\n}\n```\n\n`pe` comes from `errors.As`, so it points at whatever value the application returned. Returning a package level sentinel is the idiomatic way to express a reusable error, and the same pointer then reaches the handler on every request that returns it:\n\n```go\nvar ErrWidgetNotFound = &echo.ProblemError{Status: http.StatusNotFound, Detail: \"no such widget\"}\n\nfunc handler(c *echo.Context) error {\n return ErrWidgetNotFound\n}\n```\n\nTwo things go wrong. Concurrent requests write to the same struct, which the race detector reports:\n\n```\nWARNING: DATA RACE\nWrite at 0x... by goroutine 10:\nPrevious read at 0x... by goroutine 33:\n```\n\nAnd the write is permanent. After the first request the sentinel is no longer the value the application declared; `Type` has become `\"about:blank\"` and `Title` has become `\"Not Found\"`. An application that later inspects or re-serializes its own error sees fields it never set.\n\nThe `ProblemErrorer` path has the same shape whenever `ProblemError()` returns a shared pointer.\n\n## The change\n\nThe defaults are applied to a copy, so the response is unchanged and the caller's value is left alone. Nothing else about the handler moves.\n\n## Testing\n\n`TestProblemDetailsHTTPErrorHandler_DoesNotMutateSharedProblem` serves one request that returns a sentinel, checks the response still carries the fully defaulted body, and then compares the sentinel with a copy taken before the request.\n\nAgainst the current cod\n...[truncated]", "pr_title": "fix(rfc9457): do not mutate a shared ProblemError"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "90702e71a7cde342da70b1f97e8e6420c509f939", "candidate_corpus": {"base_commit": "90702e71a7cde342da70b1f97e8e6420c509f939", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "b59b347c95f78066152782c21e3c315088b49c79", "negative_distractors": [], "related_tests": ["middleware/body_limit_test.go"], "root_cause_files": ["bind.go", "json.go", "middleware/body_limit.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "df86d343d6a835697a9db81a", "metadata": {"confidence": "weak", "created_at": "2026-09-06T12:05:03Z", "evidence": {"implementation_files": ["bind.go", "json.go", "middleware/body_limit.go"], "related_tests": ["middleware/body_limit_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-09-29T19:45:18Z", "pr": 3087, "pr_url": "https://github.com/labstack/echo/pull/3087"}, "query": {"changed_file_summary": "3 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 3, "implementation_files": ["bind.go", "json.go", "middleware/body_limit.go"], "pr_body": "## Problem\n\nWith unknown `Content-Length`, `BodyLimit` forwarded an unbounded read to the underlying body. A caller that processes the returned `n > 0` bytes could receive more than the configured limit. The v4.15.2 JSON example in #3071 also accepted an oversized body. Current v5 uses `ReadFrom` followed by `json.Unmarshal` for default JSON binding, so that particular Bind bypass does not reproduce on v5; its read error was instead reported as HTTP 400.\n\n## Changes\n\n- Cap each underlying read at `remaining + 1`, return only bytes within the limit, and make the 413 error sticky after overflow.\n- Give each request its own reader. `req.Body` remains valid for outer middleware and code that uses it after the handler returns.\n- Reject negative `LimitBytes` in `ToMiddleware`.\n- Preserve status-coded body read errors through JSON, XML, form, and multipart binding, so an oversized body returns HTTP 413.\n\nThis reader retains Echo's status-coded error contract. Unlike `http.MaxBytesReader`, it does not signal `net/http` to close the connection after overflow; that is existing BodyLimit behavior and can be evaluated separately.\n\n## Verification\n\n- Regression tests cover oversized reads, exact-size bodies, `math.MaxInt64`, source errors, reader lifetime, invalid configuration, and HTTP 413 from JSON, XML, form, and multipart binding.\n- `go test ./... -count=1` passes on the PR branch and with this patch applied to the latest tracked master commit.\n- `go vet ./...` and `go test -race ./middleware -run TestBodyLimit -count=1` pass.\n\nRefs #3071. The v4 backport is still needed before closing the issue.", "pr_title": "fix(middleware): prevent BodyLimit bypass with contract-compliant readers"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "05489dc1730161df26b72d1ae2a3ba6fb8178fc7", "candidate_corpus": {"base_commit": "05489dc1730161df26b72d1ae2a3ba6fb8178fc7", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "4ec116dc9b5bff1da7513c0dc86095d0e8ce9654", "negative_distractors": [], "related_tests": ["middleware/csrf_test.go"], "root_cause_files": ["middleware/csrf.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "aa6a5ae9ef6cfe86c14bc788", "metadata": {"confidence": "weak", "created_at": "2026-08-20T05:56:42Z", "evidence": {"implementation_files": ["middleware/csrf.go"], "related_tests": ["middleware/csrf_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-20T06:30:07Z", "pr": 3067, "pr_url": "https://github.com/labstack/echo/pull/3067"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["middleware/csrf.go"], "pr_body": "## Problem\n\nIf `TokenLookup` uses a source keyword that isn't recognized, CSRF silently\nstops checking tokens.\n\nThe known sources are `header`, `query`, `param`, `cookie`, `form`. A small typo\nlike `Header:X-CSRF-Token` (capital H) or `cookies:_csrf` (should be `cookie`)\nmatches none of them, and there's no `default` case, so it's just dropped. If\nevery source in the lookup is like that you end up with zero extractors and no\nerror. CSRF then loops over an empty list, finds nothing to validate, and lets\nthe request through. So a typo in the config turns CSRF off without any warning.\n\nKeyAuth already guards against this:\n\n // middleware/key_auth.go\n if len(extractors) == 0 {\n return nil, errors.New(\"echo key-auth middleware could not create extractors from KeyLookup string\")\n }\n\nCSRF just doesn't have the same check, so this PR adds it.\n\nFor context on impact: this only happens with a misconfigured `TokenLookup`, and\n`Sec-Fetch-Site` still blocks normal cross-site requests. But a security\nmiddleware quietly doing nothing on a typo felt worth turning into an error.\n\n## Change\n\n- `CSRFConfig.ToMiddleware()` now returns an error when `TokenLookup` produces no\n extractors (e.g. `\"echo csrf middleware could not create extractors from TokenLookup string\"`),\n matching KeyAuth. `CSRFWithConfig` turns that error into a startup panic.\n- Added a test case.\n\nValid configs keep working; only a lookup where all sources are unknown is\nrejected.", "pr_title": "fix(middleware): reject CSRF TokenLookup that produces no extractors"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "a2dea4e610069a3d0fda7844ca456a63ee0e5f7b", "candidate_corpus": {"base_commit": "a2dea4e610069a3d0fda7844ca456a63ee0e5f7b", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "05489dc1730161df26b72d1ae2a3ba6fb8178fc7", "negative_distractors": [], "related_tests": ["middleware/cors_test.go"], "root_cause_files": ["middleware/cors.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "772a9ad90c90694fbd6860e3", "metadata": {"confidence": "weak", "created_at": "2026-07-23T10:49:25Z", "evidence": {"implementation_files": ["middleware/cors.go"], "related_tests": ["middleware/cors_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-08-04T05:11:58Z", "pr": 3060, "pr_url": "https://github.com/labstack/echo/pull/3060"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["middleware/cors.go"], "pr_body": "## Problem\n\nCORS middleware treated **every** `OPTIONS` request as a preflight and short-circuited with `204`, so user-registered `OPTIONS` handlers never ran.\n\nPer the [Fetch standard](https://fetch.spec.whatwg.org/#cors-preflight-request), a preflight is an `OPTIONS` request that includes **both**:\n\n- `Origin`\n- `Access-Control-Request-Method`\n\nThese are **not** preflights and should reach the next handler:\n\n```bash\ncurl -X OPTIONS localhost:8080/hello\ncurl -X OPTIONS -H 'Origin: https://example.com' localhost:8080/hello\n```\n\nThis one **is** a preflight and should still be handled by the middleware:\n\n```bash\ncurl -X OPTIONS \\\n -H 'Origin: https://example.com' \\\n -H 'Access-Control-Request-Method: PUT' \\\n localhost:8080/hello\n```\n\nFixes #2534.\n\n## Change\n\n- Add `isCORSPreflight` requiring method + Origin + ACR-Method\n- Non-preflight `OPTIONS` continues the chain via `next(c)`\n- Real preflights keep the existing short-circuit + CORS headers\n- Still copy router `Allow` onto `OPTIONS` responses when present\n\n## Tests\n\n- `TestIsCORSPreflight`\n- `TestCORS_NonPreflightOPTIONSPassThrough` (covers the three cases above)\n- Existing preflight cases updated to send `Access-Control-Request-Method`\n\n```text\ngo test ./middleware/ -run 'CORS|IsCORSPreflight'\n```", "pr_title": "fix(middleware): classify CORS preflight per Fetch standard"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "ed8bbe4b6cbf519766c99e492b9cc427404b3719", "candidate_corpus": {"base_commit": "ed8bbe4b6cbf519766c99e492b9cc427404b3719", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "79b496800f75fe4a83835719842847a9d5b25c3e", "negative_distractors": [], "related_tests": ["middleware/decompress_test.go"], "root_cause_files": ["middleware/decompress.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "b1a4b47926537b83b75a2110", "metadata": {"confidence": "weak", "created_at": "2026-07-22T05:43:40Z", "evidence": {"implementation_files": ["middleware/decompress.go"], "related_tests": ["middleware/decompress_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-07-23T05:02:10Z", "pr": 3056, "pr_url": "https://github.com/labstack/echo/pull/3056"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["middleware/decompress.go"], "pr_body": "## Summary\nDecompress middleware only accepted exact `Content-Encoding: gzip`. Values like `Gzip` or `GZIP` were skipped.\n\n## Change\n- Compare with `strings.EqualFold` after trim.\n- Add regression tests for common case variants.\n\n## Test plan\n- [x] `go test ./middleware -run TestDecompress`", "pr_title": "fix(middleware): match gzip Content-Encoding case-insensitively"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "ed8bbe4b6cbf519766c99e492b9cc427404b3719", "candidate_corpus": {"base_commit": "ed8bbe4b6cbf519766c99e492b9cc427404b3719", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "a45f07d7e4e0655424f56bc9964f395c7d6dc0ec", "negative_distractors": [], "related_tests": ["context_test.go"], "root_cause_files": ["context.go", "ip.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "43ebbf03a5afa20b5dc139f6", "metadata": {"confidence": "weak", "created_at": "2026-07-22T05:41:30Z", "evidence": {"implementation_files": ["context.go", "ip.go"], "related_tests": ["context_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-07-23T05:27:31Z", "pr": 3054, "pr_url": "https://github.com/labstack/echo/pull/3054"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 2, "implementation_files": ["context.go", "ip.go"], "pr_body": "## Summary\n`Context.RealIP()` (and the `LegacyIPExtractor` fallback) used `net.SplitHostPort` and ignored the error, so a bare IP `RemoteAddr` (no `:port`) returned an empty string.\n\n## Change\n- Fall back through `extractIP`, the same helper used by `ExtractIPDirect`.\n- Add unit tests for bare IPv4 and IPv6 `RemoteAddr` values.\n\n## Test plan\n- [x] `go test . -run TestContext_RealIP`", "pr_title": "fix: resolve RealIP for bare RemoteAddr without port"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "70b31c2ca5131f4eda9c56d78294e8a0573f8645", "candidate_corpus": {"base_commit": "70b31c2ca5131f4eda9c56d78294e8a0573f8645", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "2caa1a52ff35d921251bd4e72dcd8fcef094ea88", "negative_distractors": [], "related_tests": ["middleware/static_test.go"], "root_cause_files": ["middleware/static.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "defb86c2d0d02ad1bd8bf8fc", "metadata": {"confidence": "weak", "created_at": "2026-07-14T23:43:21Z", "evidence": {"implementation_files": ["middleware/static.go"], "related_tests": ["middleware/static_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-07-16T19:01:26Z", "pr": 3043, "pr_url": "https://github.com/labstack/echo/pull/3043"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["middleware/static.go"], "pr_body": "Fixes #2775\n\nPreserves 404 responses from matched handlers when HTML5 static fallback is enabled, while retaining the index fallback for router misses, including group route-not-found handling.\n\nVerification:\n- `go test -race ./middleware -run '^TestStaticHTML5PreservesMatchedHandlerNotFound$' -count=1`\n- `go test -race ./middleware -run '^TestStatic$/^ok,_when_html5_mode_serve_index_for_any_static_file_that_does_not_exist$' -count=1`\n- `go test -race ./middleware`", "pr_title": "fix(static): preserve matched handler 404s"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "70b31c2ca5131f4eda9c56d78294e8a0573f8645", "candidate_corpus": {"base_commit": "70b31c2ca5131f4eda9c56d78294e8a0573f8645", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "77ac3264d089db470913df36ef0ff88f4cabaf8c", "negative_distractors": [], "related_tests": ["json_test.go", "perf_bench_test.go"], "root_cause_files": ["bind.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "4c66f92342d1d2058879d93c", "metadata": {"confidence": "weak", "created_at": "2026-07-14T09:46:12Z", "evidence": {"implementation_files": ["bind.go"], "related_tests": ["json_test.go", "perf_bench_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-07-16T19:04:01Z", "pr": 3042, "pr_url": "https://github.com/labstack/echo/pull/3042"}, "query": {"changed_file_summary": "1 implementation files and 2 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["bind.go"], "pr_body": "Use Go's range-over-integer syntax where the index is either needed directly or not used. This simplifies the loops without changing behavior.", "pr_title": "refactor: use range-over-integer loops"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "25685e6f5f7b0683105d1386db46ae48eb3de028", "candidate_corpus": {"base_commit": "25685e6f5f7b0683105d1386db46ae48eb3de028", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "c3fa2a27ff92b2b8db360de614f999ef1da24725", "negative_distractors": [], "related_tests": ["echo_fs_test.go", "middleware/static_test.go"], "root_cause_files": ["echo_fs.go", "internal/pathutil/pathutil.go", "middleware/static.go"], "root_cause_symbols": [], "supporting_files": ["echo_fs_encoded_separator_test.go", "internal/pathutil/pathutil_test.go", "middleware/static_encoded_separator_test.go"]}, "id": "076c9cd67e342c2dc8736a37", "metadata": {"confidence": "weak", "created_at": "2026-06-14T15:30:30Z", "evidence": {"implementation_files": ["echo_fs.go", "internal/pathutil/pathutil.go", "middleware/static.go"], "related_tests": ["echo_fs_test.go", "middleware/static_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-06-14T16:15:53Z", "pr": 3011, "pr_url": "https://github.com/labstack/echo/pull/3011"}, "query": {"changed_file_summary": "3 implementation files and 2 existing test files changed within 8 total files.", "implementation_file_count": 3, "implementation_files": ["echo_fs.go", "internal/pathutil/pathutil.go", "middleware/static.go"], "pr_body": "v4 backport of #3009 (released in v5.2.0) for **GHSA-vfp3-v2gw-7wfq**.\n\n## Summary\nAn encoded path separator (`%2F` or `%5C`) in a static file URL could bypass route-level access control and disclose files. The router matches against the raw, still-encoded path, so `%2F` is not a separator — `/admin%2Fsecret.txt` skips a protected `/admin/*` group, falls through to static serving, which then unescaped `%2F`→`/` and served `admin/secret.txt`.\n\nv4 is affected on **both** static surfaces:\n- `echo_fs.go` `StaticDirectoryHandler` (used by `Static`/`StaticFS`) — vulnerable to `%2F` **and** `%5C` (it used OS-specific `filepath.Clean`).\n- `middleware/static.go` — vulnerable to `%2F` (it already used `path.Clean`, so not `%5C`).\n\n## Fix\n- Both surfaces reject a wildcard containing an encoded separator (`%2F`/`%2f` or `%5C`/`%5c`) with `404` before unescaping, via a shared `internal/pathutil` helper.\n- `StaticDirectoryHandler` switched from `filepath.Clean`+`ToSlash` to `path.Clean` (OS-independent; keeps backslash literal on Windows).\n\n## Tests\n- New regression tests for `%2F`, `%5C`, double-encoded `%252F`, group `StaticFS`, and the static middleware on a group; unit test for the detector.\n- Updated two existing cases (`open redirect vulnerability`, `Directory redirect#01`) that asserted the old `%2f`-unescaped redirect — they now correctly assert `404` + no `Location`.\n- `go test -race ./...` and `go vet ./...` pass.\n\nTargets the **v4** branch for a **v4.15.3** release; the advisory will be amended to add the `github.com/labstack/echo` (v4) affected product once tagged.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)", "pr_title": "fix(static): reject encoded path separators that bypass route-level middleware (v4 backport)"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "c9477eb5b5126ae933f2729af852d1be3f5845ae", "candidate_corpus": {"base_commit": "c9477eb5b5126ae933f2729af852d1be3f5845ae", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "8d1ae9d3360a71672418856d58753af25f2c3986", "negative_distractors": [], "related_tests": ["echo_test.go", "middleware/static_test.go"], "root_cause_files": ["echo.go", "internal/pathutil/pathutil.go", "middleware/static.go"], "root_cause_symbols": [], "supporting_files": ["internal/pathutil/pathutil_test.go", "static_encoded_separator_test.go"]}, "id": "0fd7611549bf8f6ae06de74c", "metadata": {"confidence": "weak", "created_at": "2026-06-14T13:25:55Z", "evidence": {"implementation_files": ["echo.go", "internal/pathutil/pathutil.go", "middleware/static.go"], "related_tests": ["echo_test.go", "middleware/static_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-06-14T14:04:59Z", "pr": 3009, "pr_url": "https://github.com/labstack/echo/pull/3009"}, "query": {"changed_file_summary": "3 implementation files and 2 existing test files changed within 7 total files.", "implementation_file_count": 3, "implementation_files": ["echo.go", "internal/pathutil/pathutil.go", "middleware/static.go"], "pr_body": "## Summary\n\nFixes an access-control bypass / static file disclosure where an **encoded slash (`%2F`) lets a request skip a protected route group yet still resolve the file on disk** (GHSA-vfp3-v2gw-7wfq, CWE-22).\n\nThe router matches routes against the raw, still-encoded request path, so `%2F` is **not** treated as a path separator — `/admin%2Fsecret.txt` is a single segment and never matches a protected `/admin/*` group. The request falls through to the static handler, which then `url.PathUnescape`d `%2F` back to `/` and resolved `admin/secret.txt` from disk. Router and file handler disagreed on what counts as a separator.\n\n### Reproduction (before)\n```\nGET /admin/secret.txt -> 403 (protected group fires)\nGET /admin%2Fsecret.txt -> 200 body=\"TOP-SECRET\" ← bypass + disclosure\n```\n\nCommon affected pattern:\n```go\nadminGroup := e.Group(\"/admin\", authMiddleware)\ne.StaticFS(\"/\", os.DirFS(\"public\"))\n```\n\n## Fix\n\n`StaticDirectoryHandler` now rejects a wildcard containing an encoded path separator (`%2F`/`%2f` or `%5C`/`%5c`) with `404` **before** unescaping, keeping the router and the file handler consistent. No real filename contains a path separator, so legitimate static requests are unaffected.\n\n## Tests\n- New `static_encoded_separator_test.go`: regression test for the bypass + unit test for the `%2F`/`%5C` detector (incl. lower-case hex and a benign `%25` case).\n- Updated the existing `TestEcho_StaticFS` \"open redirect\" case: `…%2f..` now returns `404` with **no redirect emitted at all** (was a sanitized `301`), which closes that vector harder.\n- `go test ./ ./middleware/` and `go vet ./` pass.\n\n## Scope / notes\n- This addresses the **static-disclosure** vector. The related report GHSA-xr3h-5475-xgqr (percent-encoded routing bypassing protected middleware on *non-st\n...[truncated]", "pr_title": "fix(static): reject encoded path separator to prevent route-level auth bypass"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "a9ede66a5a7196411131beb1ee801e75bbaf7ac6", "candidate_corpus": {"base_commit": "a9ede66a5a7196411131beb1ee801e75bbaf7ac6", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "b1d65e40fef366f2e1a70ca7c172f5057df7024b", "negative_distractors": ["middleware/secure.go", "middleware/util.go"], "related_tests": ["server_test.go"], "root_cause_files": ["bind.go", "context.go", "echo.go", "middleware/secure.go", "middleware/util.go"], "root_cause_symbols": [], "supporting_files": ["bind_cache_test.go", "dispatch_pool_test.go", "middleware/randomstring_bench_test.go", "middleware/randomstring_concurrent_test.go", "perf_bench_test.go", "query_fastpath_test.go"]}, "id": "b99efc18965fe3769a8a91dd", "metadata": {"confidence": "weak", "created_at": "2026-06-14T00:08:41Z", "evidence": {"implementation_files": ["bind.go", "context.go", "echo.go", "middleware/secure.go", "middleware/util.go"], "related_tests": ["server_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "cross_directory_test", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-06-14T13:08:08Z", "pr": 3008, "pr_url": "https://github.com/labstack/echo/pull/3008"}, "query": {"changed_file_summary": "5 implementation files and 1 existing test files changed within 12 total files.", "implementation_file_count": 5, "implementation_files": ["bind.go", "context.go", "echo.go", "middleware/secure.go", "middleware/util.go"], "pr_body": "## Summary\n\nOptimizes Echo's per-request hot paths to remove avoidable allocations and CPU work. **No public API changes; the standard-library JSON serializer remains the default.** All numbers are `benchstat` medians (n=8, Apple M3 Max / arm64, Go 1.26).\n\n> **Note (per @aldas review):** the opt-in sonic serializer was **removed** from this PR — it belongs in `echox/cookbook` as a runnable example, not as a submodule in core. This PR is now purely core hot-path optimizations. See \"Using a faster JSON encoder\" below.\n\n## What changed\n\n**Core**\n- **Middleware chain compiled once** (`echo.go`, `buildRouterChains`) and reused, instead of re-wrapping closures on every request. Routing stores the matched handler on the `Context`.\n- **Context** (`context.go`): zero-copy `String`/`HTML`/`JSONP` writes (write-only `unsafe` view), reuse of `delayedStatusWriter` (guarded against re-entrant `c.JSON`) and the store map across requests, inline `Get`/`Set` unlock, and a single-key `QueryParam` fast path proven byte-for-byte equal to `url.ParseQuery().Get` (incl. malformed escapes / `;` / `+`).\n- **Binder** (`bind.go`): per-`reflect.Type` field-metadata cache so struct tags are parsed once per type, not per request. Preserves the field-name error wrapping from #3005.\n- **Middleware**: precompute the HSTS header once (`secure.go`); pool the request-ID `randomString` scratch buffers (`util.go`).\n- New hot-path benchmark suite + pooling/dispatch regression tests.\n- `test:` de-flake `TestStartConfig_WithListenerNetwork` (ephemeral port instead of a hard-coded one) — separable commit; fixes a pre-existing CI flake.\n\n## Performance (before → after)\n\n| Path | Before | After | Δ time | Allocs |\n|---|--:|--:|--:|:--:|\n| 5-middleware request | 101 ns | **34 ns** | **−66%** | 5 → **0** |\n| `Set`\n...[truncated]", "pr_title": "perf: optimize core hot paths (chain, context, binding, responses)"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "4f5ac600f8fb69a33c45430ea8263de02ed0b494", "candidate_corpus": {"base_commit": "4f5ac600f8fb69a33c45430ea8263de02ed0b494", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "ec9515a829f6e7ae76c5187e7cc249ddf21181d9", "negative_distractors": [], "related_tests": ["bind_test.go"], "root_cause_files": ["bind.go"], "root_cause_symbols": [], "supporting_files": ["bind_field_error_test.go"]}, "id": "fa525c7032dff3129de17d21", "metadata": {"confidence": "weak", "created_at": "2026-06-13T20:10:10Z", "evidence": {"implementation_files": ["bind.go"], "related_tests": ["bind_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-06-13T20:22:36Z", "pr": 3005, "pr_url": "https://github.com/labstack/echo/pull/3005"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["bind.go"], "pr_body": "## Problem (#2629)\n\nWhen `c.Bind()` fails a type conversion on form/struct data, the error gives no indication of *which* field failed:\n\n```\nPOST /submit number=10a\n→ code=400, message=Bad Request, err=strconv.ParseInt: parsing \"10a\": invalid syntax\n```\n\nThis makes it hard to render a useful validation message (\"the `number` field must be an integer\").\n\n## Fix\n\n`bindData` already has the field name (`inputFieldName`) in scope at each conversion site but returned the bare error. Wrap those returns with the field name using `%w` (so `errors.Is`/`errors.As` still work):\n\n```\n→ code=400, message=Bad Request, err=number: strconv.ParseInt: parsing \"10a\": invalid syntax\n```\n\nThis is the wrap the reporter proposed in the thread (`fmt.Errorf(\"%s: %w\", inputFieldName, err)`), applied to all four conversion-error sites (unmarshaler, slice element, scalar).\n\n## Test\n\n`TestBind_formConversionErrorIncludesFieldName` (written first; fails on master — error contains no field name). Four existing tests that asserted the bare message are updated to the field-prefixed form. gofmt/vet clean; full root-package suite passes.\n\nFixes #2629.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)", "pr_title": "fix(binder): include field name in bind conversion errors (#2629)"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "6a390cb5a791c12993140e00e66090e67511b9a0", "candidate_corpus": {"base_commit": "6a390cb5a791c12993140e00e66090e67511b9a0", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "9c748c9b114372d9a9326405a0b063b84a31147d", "negative_distractors": [], "related_tests": ["middleware/body_limit_test.go", "middleware/decompress_test.go"], "root_cause_files": ["middleware/decompress.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "25b231c427916f26ee1aeab8", "metadata": {"confidence": "weak", "created_at": "2026-06-10T18:19:23Z", "evidence": {"implementation_files": ["middleware/decompress.go"], "related_tests": ["middleware/body_limit_test.go", "middleware/decompress_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-06-11T06:00:26Z", "pr": 3000, "pr_url": "https://github.com/labstack/echo/pull/3000"}, "query": {"changed_file_summary": "1 implementation files and 2 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["middleware/decompress.go"], "pr_body": "## Summary\n\nFix `Decompress` so middleware after it does not keep using the compressed request size after the body has been replaced with the decoded gzip stream.\n\nFor example:\n\n```go\ne.Use(middleware.Decompress())\ne.Use(middleware.BodyLimit(4))\n```\n\nA gzipped request whose decoded body is `ok` should pass:\n\n```bash\nprintf \"ok\" | gzip | curl -X POST \\\n -H \"Content-Type: text/plain\" \\\n -H \"Content-Encoding: gzip\" \\\n --data-binary @- \\\n http://localhost:8080/\n```\n\nBefore this change, `Decompress` replaced `req.Body` but left `req.ContentLength` set to the compressed size, so `BodyLimit` could reject the request before reading it:\n\n```text\n{\"message\":\"Request Entity Too Large\"}\n```\n\nWith this change, `Decompress` sets `req.ContentLength = -1` after gzip decompression is set up, so downstream middleware enforces limits while reading the decoded body:\n\n```text\nok\n```\n\nThis intentionally does not change `Content-Encoding`, `GetBody`, or multiple content-coding behavior.\n\n## Test plan\n\n- [x] `go test -count=1 ./...`\n- [x] `go test -race -count=1 ./...`\n- [x] `go vet ./...`\n- [x] `staticcheck ./...`\n- [x] Manual curl check with the same handler returned `ok` and HTTP 200", "pr_title": "fix(middleware): reset ContentLength after gzip decompression"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "222be90c0e074f62161e6c2076793ee892fc111d", "candidate_corpus": {"base_commit": "222be90c0e074f62161e6c2076793ee892fc111d", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "2d9b2aa34ef4fd9de1fc2614a4bb79a414e194b4", "negative_distractors": ["router.go"], "related_tests": ["echo_test.go", "group_test.go"], "root_cause_files": ["echo.go", "group.go", "route.go", "router.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "ff23078a30b8d853cd1e1f79", "metadata": {"confidence": "weak", "created_at": "2026-06-08T19:54:52Z", "evidence": {"implementation_files": ["echo.go", "group.go", "route.go", "router.go"], "related_tests": ["echo_test.go", "group_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:37+00:00", "merged_at": "2026-07-12T19:37:47Z", "pr": 2996, "pr_url": "https://github.com/labstack/echo/pull/2996"}, "query": {"changed_file_summary": "4 implementation files and 2 existing test files changed within 6 total files.", "implementation_file_count": 4, "implementation_files": ["echo.go", "group.go", "route.go", "router.go"], "pr_body": "FIX: https://github.com/labstack/echo/issues/2950\n\nRevert back to v4 behavior for group registering implicit 404 handlers. This will fix: CORS middleware doesnt automatically handle OPTIONS routes for groups anymore since upgrade to v5.\n\nThis is a breaking change in `v5`. It reverts back to `v4` behavior.", "pr_title": "Revert back to v4 behavior for group registering implicit 404 handler…"}, "query_provenance": "pr_summary", "repo": "labstack/echo", "task_type": "code2test", "version": 2} +{"base_commit": "61968e893eee2f27696c2fbc8e34fa5c4afaf7c4", "candidate_corpus": {"base_commit": "61968e893eee2f27696c2fbc8e34fa5c4afaf7c4", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "746ef07158728502482cea9f880a6f4b21ef29a9", "negative_distractors": [], "related_tests": ["completions_test.go"], "root_cause_files": ["completions.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "4b167764743a0ce331ec84ea", "metadata": {"confidence": "weak", "created_at": "2026-02-10T08:14:44Z", "evidence": {"implementation_files": ["completions.go"], "related_tests": ["completions_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2026-04-24T20:41:58Z", "pr": 2356, "pr_url": "https://github.com/spf13/cobra/pull/2356"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["completions.go"], "pr_body": "## Summary\n\n- Fixes a bug where `getCompletions()` accidentally mutates `os.Args` by writing `\"--\"` into the shared backing array via an `append` with spare capacity\n- Uses a three-index slice expression (`finalArgs[:len:len]`) to cap the slice capacity, forcing `append` to allocate a new array\n- Adds a regression test that confirms the args slice is not corrupted during shell completion\n\n## Details\n\nWhen shell completions are requested (e.g., `prog __complete x`), `getCompletions()` calls:\n\n```go\n_ = finalCmd.ParseFlags(append(finalArgs, \"--\"))\n```\n\n`finalArgs` is a sub-slice of the original args (derived from `os.Args[1:]`), and if it has spare capacity in its backing array, `append` writes `\"--\"` directly into the shared memory rather than allocating a new slice. This corrupts `os.Args`, which users may be inspecting in their `ValidArgsFunction`.\n\nThe fix uses `finalArgs[:len(finalArgs):len(finalArgs)]` to limit the capacity to the length, guaranteeing that `append` allocates a fresh backing array.\n\nThe bug is most visible with `TraverseChildren: true`, since `Traverse()` returns sub-slices that preserve the original backing array's capacity.\n\nFixes #2257\n\n## Test plan\n\n- [x] Added `TestCompletionDoesNotMutateArgs` that fails without the fix and passes with it\n- [x] Full test suite passes (`go test ./...`)", "pr_title": "fix: prevent completions from mutating os.Args via append side effect"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "f98cf4216d3cb5235e6e0cd00ee00959deb1dc65", "candidate_corpus": {"base_commit": "f98cf4216d3cb5235e6e0cd00ee00959deb1dc65", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "1995054b003053cc1e404bccfbf6d168e8731509", "negative_distractors": [], "related_tests": ["command_test.go"], "root_cause_files": ["command.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "7162c19ac46ee8939d5ed1cc", "metadata": {"confidence": "weak", "created_at": "2025-02-20T15:05:06Z", "evidence": {"implementation_files": ["command.go"], "related_tests": ["command_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2025-02-21T12:46:15Z", "pr": 2241, "pr_url": "https://github.com/spf13/cobra/pull/2241"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["command.go"], "pr_body": "Fixes https://github.com/spf13/cobra/issues/2240", "pr_title": "Flow context to command in SetHelpFunc"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "a97f9fd47b290016526c8af2dac0531fea5cd773", "candidate_corpus": {"base_commit": "a97f9fd47b290016526c8af2dac0531fea5cd773", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "40b5bc1437a564fc795d388b23835e84f54cd1d1", "negative_distractors": [], "related_tests": ["command_test.go"], "root_cause_files": ["command.go"], "root_cause_symbols": [], "supporting_files": ["command_go120.go", "command_go121.go"]}, "id": "5f5ea9184e261dbd8aa2511e", "metadata": {"confidence": "weak", "created_at": "2025-02-16T21:50:39Z", "evidence": {"implementation_files": ["command.go"], "related_tests": ["command_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2025-02-16T23:42:04Z", "pr": 2235, "pr_url": "https://github.com/spf13/cobra/pull/2235"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 1, "implementation_files": ["command.go"], "pr_body": "This reverts commit d1e9d85fcf592461f3bc2f4b6d5e140c4c0aabf8.\n\nSome programs set os.Args in their unit tests and this change would break those tests.\n\nRef: https://github.com/spf13/cobra/pull/2173#issuecomment-2661544195", "pr_title": "Revert \"Make detection for test-binary more universal (#2173)\""}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "17b6dca2ffaf6113cbd1cf433ec988fa7d63c6f3", "candidate_corpus": {"base_commit": "17b6dca2ffaf6113cbd1cf433ec988fa7d63c6f3", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "8cb30f9ca53a004a6fe88c5cfcc79ac7b24fc638", "negative_distractors": [], "related_tests": ["completions_test.go"], "root_cause_files": ["active_help.go", "command.go", "completions.go"], "root_cause_symbols": [], "supporting_files": ["site/content/active_help.md", "site/content/completions/_index.md"]}, "id": "4e4746ffd4103de1ab6eb584", "metadata": {"confidence": "weak", "created_at": "2025-02-08T01:05:12Z", "evidence": {"implementation_files": ["active_help.go", "command.go", "completions.go"], "related_tests": ["completions_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2025-02-09T16:06:07Z", "pr": 2231, "pr_url": "https://github.com/spf13/cobra/pull/2231"}, "query": {"changed_file_summary": "3 implementation files and 1 existing test files changed within 6 total files.", "implementation_file_count": 3, "implementation_files": ["active_help.go", "command.go", "completions.go"], "pr_body": "The code has also been refactored to use a type alias for completion and a completion helper\n\nUsing a type alias is a non-breaking change, and it makes the code more readable and easier to understand.\n\nFixes #2222", "pr_title": "feat: add CompletionWithDesc helper"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "4ba5566f5704a9c0d205e1ef3efc4896156d33fa", "candidate_corpus": {"base_commit": "4ba5566f5704a9c0d205e1ef3efc4896156d33fa", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "ab5cadcc1bbe224b329726fc5f8b99d6f93e9805", "negative_distractors": [], "related_tests": ["command_test.go"], "root_cause_files": ["command.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "aa308efbeb2ee307911f873c", "metadata": {"confidence": "weak", "created_at": "2025-02-02T17:19:01Z", "evidence": {"implementation_files": ["command.go"], "related_tests": ["command_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2025-02-06T15:25:45Z", "pr": 2229, "pr_url": "https://github.com/spf13/cobra/pull/2229"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["command.go"], "pr_body": "Follow-up to #1956.\n\nThis commit allows a program to reset any of the three templates to their default behaviour, as it was possible to do before the change of #1956.\n\nFor example, one could imagine that a program could call `SetUsageTemplate(\"{{A short help}}\")`, but if a particular set of arguments is passed in by the user, the program would want to reset to the default help by calling `SetUsageTemplate(\"\")` (basically cancelling the previous call to `SetUsageTemplate()`).\n\nThis used to be possible before #1956, and this PR brings back this support.\n\nGranted, this is a bit of a corner case, but with so many programs using Cobra, let's not make any assumptions and avoid unexpected changes. \n\ncc @aarzilli @jpmcb", "pr_title": "Allow to reset the templates to the default"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "511af59cb3602540a636d8f5ed52f09e60804ce1", "candidate_corpus": {"base_commit": "511af59cb3602540a636d8f5ed52f09e60804ce1", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "5bef9d8d87ad1a1c73e74361bad9e38b3469a58e", "negative_distractors": [], "related_tests": ["command_test.go"], "root_cause_files": ["command.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "baed5ab6ef428ee992830034", "metadata": {"confidence": "weak", "created_at": "2024-08-24T03:38:53Z", "evidence": {"implementation_files": ["command.go"], "related_tests": ["command_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2024-10-12T16:08:27Z", "pr": 2180, "pr_url": "https://github.com/spf13/cobra/pull/2180"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["command.go"], "pr_body": "When writing a plugin and setting CommandDisplayNameAnnotation you want the display name to be used in help text. This did not work when setting command Version since the help text and version templates used the command Name().\n\nThis change makes command DisplayName() public, so it can be used in templates or other code that want to use this value, and fix --version help text and template to use the command DisplayName().", "pr_title": "Fix --version help and output for plugins"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "9f9056765ccb3bfb1c72a560b4c6edbff71c0f32", "candidate_corpus": {"base_commit": "9f9056765ccb3bfb1c72a560b4c6edbff71c0f32", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "d1e9d85fcf592461f3bc2f4b6d5e140c4c0aabf8", "negative_distractors": [], "related_tests": ["command_test.go"], "root_cause_files": ["command.go", "command_go120.go", "command_go121.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "522e4537cfebf5a6aea72895", "metadata": {"confidence": "weak", "created_at": "2024-07-16T16:14:18Z", "evidence": {"implementation_files": ["command.go", "command_go120.go", "command_go121.go"], "related_tests": ["command_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2024-12-28T22:07:03Z", "pr": 2173, "pr_url": "https://github.com/spf13/cobra/pull/2173"}, "query": {"changed_file_summary": "3 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 3, "implementation_files": ["command.go", "command_go120.go", "command_go121.go"], "pr_body": "**This has been reverted by #2235 in release v1.9.1**\n\n==\n\n- relates to https://github.com/spf13/cobra/pull/155\n- relates to https://github.com/docker/cli/pull/5224\n\nWhen running tests in verbose mode (or other options), tests involving Cobra may fail if the test does not explicitly set Command.args to an empty slice; in this case, Cobra defaults to using `os.Args`, which will contain arguments passed to the test (such as `-v` (verbose)).\n\nCommits e5762054c9a6429fa7c234897707d and 1ef0913976db2004980575ed815c3 implemented a workaround for this when running (unit) tests for Cobra itself, but this check is specifig to Cobra (checking for `cobra.test`), and don't work on Windows (which will have a `.exe` extension),\n\nThis patch implements a more universal check, so that users of Cobra as a module also benefit from this workaround.\n\ngo1.21 and up provides a `testing.Testing()` utility ([1]); as the Cobra module still supports Go1.16 and up, an alternative implementation was added for older versions, based on golang.org/x/mod/lazyregexp [2].\n\n[1]: https://pkg.go.dev/testing#Testing\n[2]: https://cs.opensource.google/go/x/mod/+/refs/tags/v0.19.0:internal/lazyregexp/lazyre.go;l=66-78", "pr_title": "Make detection for test-binary more universal"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "a0a6ae020bb3899ff0276067863e50523f897370", "candidate_corpus": {"base_commit": "a0a6ae020bb3899ff0276067863e50523f897370", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "41227856cd731aeeeb5a2f7203b3a4c16b81fc67", "negative_distractors": [], "related_tests": ["command_test.go"], "root_cause_files": ["command.go"], "root_cause_symbols": [], "supporting_files": ["site/content/user_guide.md"]}, "id": "95e06b34b1b0cc9a5ab2a6f1", "metadata": {"confidence": "weak", "created_at": "2023-11-12T14:05:54Z", "evidence": {"implementation_files": ["command.go"], "related_tests": ["command_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2023-12-18T00:58:57Z", "pr": 2070, "pr_url": "https://github.com/spf13/cobra/pull/2070"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["command.go"], "pr_body": "Using the new CommandDisplayNameAnnotation annotation introduced in Cobra 1.8.0.\n\nFixes help text issues with:\n- help flag usage\n- help command long description\n- usage line for command without sub commands", "pr_title": "Fixes and docs for usage as plugin"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "890302a35f578311404a462b3cdd404f34db3720", "candidate_corpus": {"base_commit": "890302a35f578311404a462b3cdd404f34db3720", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "a0a6ae020bb3899ff0276067863e50523f897370", "negative_distractors": [], "related_tests": ["completions_test.go"], "root_cause_files": ["completions.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "090bafa126d37574be779709", "metadata": {"confidence": "weak", "created_at": "2023-11-02T14:18:39Z", "evidence": {"implementation_files": ["completions.go"], "related_tests": ["completions_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2023-11-02T15:23:08Z", "pr": 2063, "pr_url": "https://github.com/spf13/cobra/pull/2063"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["completions.go"], "pr_body": "With #1943 we aimed to allow programs to have access to flag completion functions.\nThere were two issues with this change:\n1. it was not handling persistent flags (I missed that in the review)\n2. it was not similar to the existing `c.RegisterFlagCompletionFunc()` because it provided a global function, which is not as future proof.\n\nThis PR proposes a simpler API that matches the `c.RegisterFlagCompletionFunc()` API. By removing the global function `GetFlagCompletion()` we are more future proof if we ever move from a global map of flag completion functions to something associated with the command.\n\nThe commit also makes this API work with persistent flags by using `c.Flag(flagName)` instead of `c.Flags().Lookup(flagName)`.\n\nThe commit also adds unit tests.\n\ncc @jpmcb @avirtopeanu-ionos @maxlandon", "pr_title": "Improve API to get flag completion function"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "8b1eba47616566fc4d258a93da48d5d8741865f0", "candidate_corpus": {"base_commit": "8b1eba47616566fc4d258a93da48d5d8741865f0", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "b711e8760b73c6aa1b4aa1bef3a26da5926f175d", "negative_distractors": [], "related_tests": ["completions_test.go"], "root_cause_files": ["completions.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "cab9a5ef4a05e8b756739477", "metadata": {"confidence": "weak", "created_at": "2023-10-27T13:49:31Z", "evidence": {"implementation_files": ["completions.go"], "related_tests": ["completions_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2023-10-28T20:10:07Z", "pr": 2061, "pr_url": "https://github.com/spf13/cobra/pull/2061"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["completions.go"], "pr_body": "Fixes #2060\n\nWhen a command sets `DisableFlagParsing = true` it requests the responsibility of doing all the flag parsing. Therefore even the `--help/-f/--version/-v` flags should not be automatically completed by Cobra in such a case.\n\nWithout this change the `--help/-h/--version/-v` flags can end up being completed twice for plugins: one time from cobra and one time from the plugin (which has set `DisableFlagParsing = true`).", "pr_title": "Don't complete --help flag when flag parsing disabled"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "c5dacb3ea4512e6766f86907dfa7014ceb9cb041", "candidate_corpus": {"base_commit": "c5dacb3ea4512e6766f86907dfa7014ceb9cb041", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "0c72800b8dba637092b57a955ecee75949e79a73", "negative_distractors": [], "related_tests": ["command_test.go"], "root_cause_files": ["command.go"], "root_cause_symbols": [], "supporting_files": ["site/content/user_guide.md"]}, "id": "21090f61f5c77ca0cb4911e1", "metadata": {"confidence": "weak", "created_at": "2023-08-31T09:25:47Z", "evidence": {"implementation_files": ["command.go"], "related_tests": ["command_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2023-09-08T17:29:06Z", "pr": 2023, "pr_url": "https://github.com/spf13/cobra/pull/2023"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["command.go"], "pr_body": "You can change the prefix before the error message by `SetErrPrefix()`.\nIt's currently `Error:`, and now it's read from `errPrefix`.\nIt's just like the `versionTemplate` and `SetVersionTemplate()` relationship.\n\nResolve: #1281", "pr_title": "Customizable error message prefix"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "0c72800b8dba637092b57a955ecee75949e79a73", "candidate_corpus": {"base_commit": "0c72800b8dba637092b57a955ecee75949e79a73", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "890302a35f578311404a462b3cdd404f34db3720", "negative_distractors": [], "related_tests": ["command_test.go"], "root_cause_files": ["command.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "27fcad2a0f846b63a5a6f07d", "metadata": {"confidence": "weak", "created_at": "2023-08-16T16:29:05Z", "evidence": {"implementation_files": ["command.go"], "related_tests": ["command_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2023-11-02T12:15:27Z", "pr": 2018, "pr_url": "https://github.com/spf13/cobra/pull/2018"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["command.go"], "pr_body": "In this case the executable is `kubectl-plugin`, but we run it as:\n\n kubectl plugin\n\nAnd the help text should reflect the actual usage of the command.\n\nTo create a plugin, add the cobra.CommandDisplayNameAnnotation:\n\n rootCmd := &cobra.Command{\n Use: \"plugin\",\n Annotations: map[string]string{\n cobra.CommandDisplayNameAnnotation: \"kubectl plugin\",\n }\n }\n\nInternally this change modifies CommandPath() for the root command to\nreturn the command display name instead of the command name. This is\nused for error messages, help text generation, and completions.\n\nCommandPath() is expected to have spaces and code using it already\nhandle spaces (e.g replacing with _), so hopefully this does not break\nanything.\n\nIssues:\n- Need documentation\n\nFixes: #2017", "pr_title": "Support usage as plugin for tools like kubectl"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "284f4101043c4b1faebde411caec35a7b6e36494", "candidate_corpus": {"base_commit": "284f4101043c4b1faebde411caec35a7b6e36494", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "fdee73b4a0d0be3e233b968ab038866b7cd99772", "negative_distractors": [], "related_tests": ["powershell_completions_test.go"], "root_cause_files": ["powershell_completions.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "791426746fe53718c1882667", "metadata": {"confidence": "weak", "created_at": "2023-05-16T12:34:46Z", "evidence": {"implementation_files": ["powershell_completions.go"], "related_tests": ["powershell_completions_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2023-06-19T16:16:18Z", "pr": 1960, "pr_url": "https://github.com/spf13/cobra/pull/1960"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["powershell_completions.go"], "pr_body": "This fixes an issue with program names that include a dot, in our case `podman.exe`. This was caused by the change in commit 6ba7ebbc.\n\nFixes #1853", "pr_title": "powershell: escape variable with curly brackets"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "09d5664f34e3f7571560e48ccb74c8904b671e87", "candidate_corpus": {"base_commit": "09d5664f34e3f7571560e48ccb74c8904b671e87", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "611e16c322e3b0413a9ba4e489fcd98ef904e406", "negative_distractors": [], "related_tests": ["cobra_test.go", "command_test.go"], "root_cause_files": ["cobra.go", "command.go", "completions.go"], "root_cause_symbols": [], "supporting_files": ["site/content/user_guide.md"]}, "id": "33a557c17a1b21a8976202a6", "metadata": {"confidence": "weak", "created_at": "2023-05-05T11:49:51Z", "evidence": {"implementation_files": ["cobra.go", "command.go", "completions.go"], "related_tests": ["cobra_test.go", "command_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2025-01-27T14:43:44Z", "pr": 1956, "pr_url": "https://github.com/spf13/cobra/pull/1956"}, "query": {"changed_file_summary": "3 implementation files and 2 existing test files changed within 6 total files.", "implementation_file_count": 3, "implementation_files": ["cobra.go", "command.go", "completions.go"], "pr_body": "Fixes #2015 \n\nCobra, in its default configuration, will execute a template to generate help, usage and version outputs. Text/template execution calls MethodByName and MethodByName disables dead code elimination in the Go linker, therefore all programs that make use of cobra will be linked with dead code elimination disabled, even if they end up replacing the default usage, help and version formatters with a custom function and no actual text/template evaluations are ever made at runtime.\n\nDead code elimination in the linker helps reduce disk space and memory utilization of programs. For example, for the simple example program used by TestDeadcodeElimination 40% of the final executable size is dead code. For a more realistic example, 12% of the size of Delve's executable is deadcode.\n\nThis PR changes Cobra so that, in its default configuration, it does not automatically inhibit deadcode elimination by:\n\n1. changing Cobra's default behavior to emit output for usage and help using simple Go functions instead of template execution\n2. quarantining all calls to template execution into SetUsageTemplate, SetHelpTemplate and SetVersionTemplate so that the linker can statically determine if they are reachable\n\nSee https://github.com/aarzilli/whydeadcode to help find why dead-code-elimination may not work as well as it could in your project.", "pr_title": "Allow linker to perform deadcode elimination for program using Cobra"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "dcb405a9399ed307eaa0e50f5cb1c290c8979dd4", "candidate_corpus": {"base_commit": "dcb405a9399ed307eaa0e50f5cb1c290c8979dd4", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "c81c46a015b48d9f79c73cc6f528f90eaabb0c7e", "negative_distractors": [], "related_tests": ["completions_test.go", "flag_groups_test.go"], "root_cause_files": ["flag_groups.go"], "root_cause_symbols": [], "supporting_files": ["site/content/user_guide.md"]}, "id": "34b1241c2e3efab89084c977", "metadata": {"confidence": "weak", "created_at": "2023-04-25T14:14:08Z", "evidence": {"implementation_files": ["flag_groups.go"], "related_tests": ["completions_test.go", "flag_groups_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2023-07-16T16:38:22Z", "pr": 1952, "pr_url": "https://github.com/spf13/cobra/pull/1952"}, "query": {"changed_file_summary": "1 implementation files and 2 existing test files changed within 4 total files.", "implementation_file_count": 1, "implementation_files": ["flag_groups.go"], "pr_body": "This PR addresses #1761 and #1891 - it adds a new flag group which can be used to group a set of flags of which at least one is required. If the related command is invoked and none of the flags in the group are set, the user is informed of the flag group (e.g. with two flags called 'path' and 'id'):\n\n```\nError: at least one of the flags in the group [path id] is required\n```\n\nIt is used like the other flag groups (MarkFlagsMutuallyExclusive / MarkFlagsRequiredTogether):\n\n```\ngetCmd.AddCommand(getEntryCmd)\ngetEntryCmd.MarkFlagsOneRequired(\"path\", \"id\")\n```\n\nIt can also be combined with MarkFlagsMutuallyExclusive with the same set of flags to enforce only one flag (and not more than one).", "pr_title": "Add 'one required flag' group"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "860791844ed3a2e544a9b9bbbcb14144a948ad20", "candidate_corpus": {"base_commit": "860791844ed3a2e544a9b9bbbcb14144a948ad20", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "b43be995ebb4bee335a787bd44498b91aef7619c", "negative_distractors": [], "related_tests": ["command_test.go"], "root_cause_files": ["command.go"], "root_cause_symbols": [], "supporting_files": ["user_guide.md"]}, "id": "4631854ff7d6026563b8e11b", "metadata": {"confidence": "weak", "created_at": "2022-10-24T16:05:41Z", "evidence": {"implementation_files": ["command.go"], "related_tests": ["command_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2022-10-24T16:59:25Z", "pr": 1841, "pr_url": "https://github.com/spf13/cobra/pull/1841"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["command.go"], "pr_body": "```\nFixes #1831\n\nBy moving the check for help group existence to \"ExecuteC()\" we no longer need groups to be added before AddCommand() is called. This provides more flexibility to developers and works better with the use of \"init()\" for command creation.\n\nSigned-off-by: Marc Khouzam \n```", "pr_title": "🍒 Cherry-pick `v1.6.x` - Check for group presence after full initialization (#1839)"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "4b9d00dfecd605048ddf3ad2a81afcab381ac1ae", "candidate_corpus": {"base_commit": "4b9d00dfecd605048ddf3ad2a81afcab381ac1ae", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "10cf7be9972ee5b5994cf760ecba642309ac8685", "negative_distractors": [], "related_tests": ["command_test.go"], "root_cause_files": ["command.go"], "root_cause_symbols": [], "supporting_files": ["user_guide.md"]}, "id": "7e523bd65afa7d644c7a3f57", "metadata": {"confidence": "weak", "created_at": "2022-10-23T21:40:02Z", "evidence": {"implementation_files": ["command.go"], "related_tests": ["command_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2022-10-24T15:11:58Z", "pr": 1839, "pr_url": "https://github.com/spf13/cobra/pull/1839"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["command.go"], "pr_body": "Fixes #1831\nReplaces #1835\n\nBy moving the check for help group existence to \"ExecuteC()\" we no longer need groups to be added before AddCommand() is called. This provides more flexibility to developers and works better with the use of \"init()\" for command creation.\n\ncc @aawsome", "pr_title": "Check for group presence after full initialization"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "bf11ab6321f2831be5390fdd71ab0bb2edbd9ed5", "candidate_corpus": {"base_commit": "bf11ab6321f2831be5390fdd71ab0bb2edbd9ed5", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "b4f979ae352828a0153281b590771ce9588d67f8", "negative_distractors": [], "related_tests": ["completions_test.go"], "root_cause_files": ["command.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "947fd5a305f790f43420f62f", "metadata": {"confidence": "weak", "created_at": "2022-09-28T08:26:50Z", "evidence": {"implementation_files": ["command.go"], "related_tests": ["completions_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2023-01-03T00:58:36Z", "pr": 1817, "pr_url": "https://github.com/spf13/cobra/pull/1817"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["command.go"], "pr_body": "Previously, arguments with a dash as the second character (e.g., 1-ff00:0:1) were detected as a flag by mistake.\nThis resulted in auto completion misbehaving if such an argument was last in the argument list during invocation.\n\nFixes #1816", "pr_title": "completions: do not detect arguments with dash as 2nd char as flag"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "cc7e235fc26cfd0b5ae36c960f399eea4badaa3e", "candidate_corpus": {"base_commit": "cc7e235fc26cfd0b5ae36c960f399eea4badaa3e", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "6b0bd3076cfafd1c108264ed1e4aa0c0fe3f8537", "negative_distractors": [], "related_tests": ["command_test.go"], "root_cause_files": ["command.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "f7575879963b4680ed4328fa", "metadata": {"confidence": "weak", "created_at": "2022-08-19T22:34:45Z", "evidence": {"implementation_files": ["command.go"], "related_tests": ["command_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2022-11-08T04:12:02Z", "pr": 1781, "pr_url": "https://github.com/spf13/cobra/pull/1781"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["command.go"], "pr_body": "When the command searches args to find the arg matching a particular subcommand name, it needs to ignore flag values, as it is possible that the value for a flag might match the name of the sub command.\n\nThis change improves argsMinusFirstX() to ignore flag values when it searches for the X to exclude from the result.\n\nFixes #1777", "pr_title": "fix: don't remove flag value that matches subcommand name"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "dbf85f6104904d539cabceebec234e817fa0df0c", "candidate_corpus": {"base_commit": "dbf85f6104904d539cabceebec234e817fa0df0c", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "22b617914c8890ba20db7ceafcdc2ef4ca4817d3", "negative_distractors": [], "related_tests": ["command_test.go"], "root_cause_files": ["command.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "949fc6731306e0b49927be8f", "metadata": {"confidence": "weak", "created_at": "2022-08-17T20:57:40Z", "evidence": {"implementation_files": ["command.go"], "related_tests": ["command_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2022-08-28T16:46:40Z", "pr": 1776, "pr_url": "https://github.com/spf13/cobra/pull/1776"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["command.go"], "pr_body": "This fixes a bug where a child flag that shadows (has the same name as) a parent persistent flag would not be shown in the child command's help output and the parent flag would be shown instead under the global flags section.\n\nThis change makes the help output consistent with the observed behavior during execution, where the child flag is the one that is actually used.\n\nThis change also allows a previously skipped/failing test to be unskipped because it passes now: `TestOverwrittenFlag`\n\nFixes #1651", "pr_title": "fix: show flags that shadow parent persistent flag in child help"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "5b11656e45a6a6579298a3b28c71f456ff196ad6", "candidate_corpus": {"base_commit": "5b11656e45a6a6579298a3b28c71f456ff196ad6", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "7039e1fa214cfc1de404ed6540158c8fda64a758", "negative_distractors": [], "related_tests": ["command_test.go"], "root_cause_files": ["command.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "88c62b548ea84bd1af37ff34", "metadata": {"confidence": "weak", "created_at": "2022-05-24T02:01:01Z", "evidence": {"implementation_files": ["command.go"], "related_tests": ["command_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2022-09-30T18:26:06Z", "pr": 1707, "pr_url": "https://github.com/spf13/cobra/pull/1707"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["command.go"], "pr_body": "In the current code, with a version set, `app help` does not display the switch option `--version`, while `app --help` does.\n\n* Fix missing '--version' flag from help command\n * with unit tests\n* Add vscode to .gitignore", "pr_title": "Fix minor annoyance of missing '--version' flag from some Help output"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "0580724b5fe33fbbff193befb787b1a1a0fe36a0", "candidate_corpus": {"base_commit": "0580724b5fe33fbbff193befb787b1a1a0fe36a0", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "70e53f62be77e03f376be845efacbd99c00024ca", "negative_distractors": [], "related_tests": ["args_test.go"], "root_cause_files": ["args.go"], "root_cause_symbols": [], "supporting_files": ["user_guide.md"]}, "id": "f96b5b4e968054ea9b2280f4", "metadata": {"confidence": "weak", "created_at": "2022-03-22T18:50:11Z", "evidence": {"implementation_files": ["args.go"], "related_tests": ["args_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2022-09-10T13:33:35Z", "pr": 1643, "pr_url": "https://github.com/spf13/cobra/pull/1643"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 3 total files.", "implementation_file_count": 1, "implementation_files": ["args.go"], "pr_body": "This is a subset of #841, which was approved by @jharshman and reviewed by @marckhouzam .\n\nFix #838 and Fix #745.\n\nThe original validators care about the number of arguments that a command accepts: `NoArgs`, `ArbitraryArgs`, `MinimumNArgs(int)`, `MaximumNArgs(int)`, `ExactArgs(int)`, `RangeArgs(min, max)`. We can consider it an enumeration of 6 items.\n\nWhen `ValidArgs` was introduced, up to six additional validators might have been added, in order to provide functions covering the full combination matrix. Certainly, `ValidArgs` is a boolean condition which is orthogonal to `Args`, because it is focused on the content of the args, not the number of them. Therefore, the full matrix covers 6 x 2 = 12 combinations. However, `NoArgs` + `ValidArgs` == `NoArgs` + `!ValidArgs`, so 11.\n\nNonetheless, the implementation was partial and a single one was introduced. Later, a second one was added. Still, there are three combinations missing, which is what was pointed out in https://github.com/spf13/cobra/issues/838 at first.\n\nHence, this PR enforces the orthogonality in the code by moving the validation of `ValidArgs` from `args.go` to `command.go`, so that:\n\n- Any validator can be used along with `ValidArgs`. `ValidArgs` is checked first, and then the defined validator.\n- `OnlyValidArgs` and `ExactValidArgs` are deprecated, but not removed.\n\nThe README is updated accordingly.", "pr_title": "deprecate ExactValidArgs and test combinations of args validators"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "19c9c7438498bf4ba07506b4eaa76670cd37ae2d", "candidate_corpus": {"base_commit": "19c9c7438498bf4ba07506b4eaa76670cd37ae2d", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "9054739e08187aab9294b7a773d54c92fabc23d3", "negative_distractors": [], "related_tests": ["completions_test.go"], "root_cause_files": ["completions.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "76eb505d682e83d70f6b6210", "metadata": {"confidence": "weak", "created_at": "2021-12-14T14:51:30Z", "evidence": {"implementation_files": ["completions.go"], "related_tests": ["completions_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2021-12-14T18:22:22Z", "pr": 1563, "pr_url": "https://github.com/spf13/cobra/pull/1563"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["completions.go"], "pr_body": "Fixes #1562\n\nPrograms that don't have sub-commands can accept any number of args.\nHowever, when doing shell completion for such programs, within the `__complete` command code this very `__complete` command makes it that the program suddenly has a sub-command, and the call to `Find() -> legacyArgs()` will then return an error if there are more than one argument on the command-line being completed.\n\nTo avoid this, we first remove the `__complete` command in such a case so as to get back to having no sub-commands.\n\nA go test has been added.\n\nSee #1562 for program to reproduce the issue.", "pr_title": "Remove __complete cmd for programs without subcmds"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "17b6dca2ffaf6113cbd1cf433ec988fa7d63c6f3", "candidate_corpus": {"base_commit": "17b6dca2ffaf6113cbd1cf433ec988fa7d63c6f3", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "24ada7fe71e3a3a8741dd52e0a7fc3b97450535a", "negative_distractors": [], "related_tests": ["completions_test.go"], "root_cause_files": ["command.go", "completions.go"], "root_cause_symbols": [], "supporting_files": ["site/content/completions/_index.md"]}, "id": "824ec55f91902606aa8132e7", "metadata": {"confidence": "weak", "created_at": "2021-12-11T19:41:44Z", "evidence": {"implementation_files": ["command.go", "completions.go"], "related_tests": ["completions_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "test_or_regression_signal", "source_test_path_overlap", "commit_detail_confirms_source_and_test_changes"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2025-02-15T18:07:03Z", "pr": 1559, "pr_url": "https://github.com/spf13/cobra/pull/1559"}, "query": {"changed_file_summary": "2 implementation files and 1 existing test files changed within 4 total files.", "implementation_file_count": 2, "implementation_files": ["command.go", "completions.go"], "pr_body": "This supersedes #1450 and #1392\n\nWhen a program has no sub-commands, its root command can accept arguments. If we add the default \"completion\" command to such programs they will now have a sub-command and will no longer accept arguments.\n\nWhat we do instead for this special case, is only add the \"completion\" command if it is being called.\n\nWe want to have the \"completion\" command for such programs because it will allow the completion of flags and of arguments (if provided by the program).\n\n@scop can you confirm this is what you were hoping for?\n\n**Testing done**\n\n```\n# Here is a program with no sub-cmds\n$ cat tests/minimal.go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/spf13/cobra\"\n)\n\nvar rootCmd = &cobra.Command{\n\tUse: \"prog\",\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tfmt.Println(\"value:\", value)\n\t\tfmt.Println(\"args:\", args)\n\t},\n}\n\nvar value string\n\nfunc main() {\n\trootCmd.Flags().StringVarP(&value, \"value\", \"e\", \"\", \"value\")\n\trootCmd.Execute()\n}\n\n$ go build -o minimal ./tests/minimal.go\n\n$ ./minimal\nvalue:\nargs: []\n$ ./minimal arg1\nvalue:\nargs: [arg1]\n$ ./minimal arg1 arg2\nvalue:\nargs: [arg1 arg2]\n$ ./minimal arg1 arg2 --value 1\nvalue: 1\nargs: [arg1 arg2]\n\n# Notice no 'completion' command visible\n$ ./minimal -h\nUsage:\n prog [flags]\n\nFlags:\n -h, --help help for prog\n -e, --value string value\n\n# But the completion command does exist\n$ ./minimal completion -h\nGenerate the autocompletion script for prog for the specified shell.\nSee each sub-command's help for details on how to use the generated script.\n\nUsage:\n prog completion [command]\n\nAvailable Commands:\n bash Generate the autocompletion script for bash\n fish Generate the autocompletion script for fish\n powershell Generate the autocompletion script for powershell\n zsh\n...[truncated]", "pr_title": "Add default completion command even if there are no other sub-commands"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} +{"base_commit": "9e1d6f1c2aa8df64b6a6ba39e92517f68580d653", "candidate_corpus": {"base_commit": "9e1d6f1c2aa8df64b6a6ba39e92517f68580d653", "type": "repo_at_base_commit"}, "gold": {"fix_commit": "f848943afd7212766aadc19256cf9e7384980281", "negative_distractors": [], "related_tests": ["command_test.go"], "root_cause_files": ["command.go"], "root_cause_symbols": [], "supporting_files": []}, "id": "9cb04e29c6fbc250866dee3f", "metadata": {"confidence": "weak", "created_at": "2021-12-06T10:17:29Z", "evidence": {"implementation_files": ["command.go"], "related_tests": ["command_test.go"], "signals": ["same_pr_changed_implementation_and_tests", "behavior_or_bug_signal", "source_test_path_overlap"], "source": "pr_level_changed_implementation_and_existing_tests"}, "generated_at": "2026-10-17T09:00:38+00:00", "merged_at": "2022-03-18T10:01:58Z", "pr": 1551, "pr_url": "https://github.com/spf13/cobra/pull/1551"}, "query": {"changed_file_summary": "1 implementation files and 1 existing test files changed within 2 total files.", "implementation_file_count": 1, "implementation_files": ["command.go"], "pr_body": "Basically the same as https://github.com/spf13/cobra/pull/1517 but uses the `Set` naming convention instead of `WithContext` \n\nContext setting without execution is important because it means that more design patterns can be achieved.\n\nCurrently I am using functional options in a project and I can add behaviour through functional options as such:\n```go\ntype GrptlOption func(*cobra.Command) error\n\nfunc WithFileDescriptors(descriptors ...protoreflect.FileDescriptor) GrptlOption {\n\treturn func(cmd *cobra.Command) error {\n\t\terr := CommandFromFileDescriptors(cmd, descriptors...)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}\n}\n```\n\nI've got a lot more options and this pattern allows me to have nice abstracted pieces of logic that interact with the cobra command. \n\nThis Pattern also allows for adding extra information to a call through `PreRun` functions:\n\n```go\n\ncmd := &cobra.Command{\n\t\tUse: \"Foobar\",\n\t\tPersistentPreRun: func(cmd *cobra.Command, args []string) {\n\t\t\terr :=cmd.SetContext(metadata.AppendToOutgoingContext(context.Background(), \"pre\", \"run\"))\n\t\t},\n\t}\n```\n\nThis is a veer nice abstraction and allows for these functions to be very modular\n\nThe issue I'm facing at the moment is that I can't write a nifty option (something like `WithAuthentication`) because that needs access to reading and setting the context. Currently I can only read the context.\n\nNeeding to use `ExecuteContext` breaks this abstraction because I need to run it right at the end.", "pr_title": "Add Command.SetContext"}, "query_provenance": "pr_summary", "repo": "spf13/cobra", "task_type": "code2test", "version": 2} diff --git a/bench/arb/extdev/data/benchmark/v2_edit2ripple/manifest.json b/bench/arb/extdev/data/benchmark/v2_edit2ripple/manifest.json new file mode 100644 index 0000000..aeb0ec3 --- /dev/null +++ b/bench/arb/extdev/data/benchmark/v2_edit2ripple/manifest.json @@ -0,0 +1,85 @@ +{ + "audit": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", + "funnel": { + "after_arb_leakage_filter": { + "Textualize/rich": 28, + "colinhacks/zod": 28, + "honojs/hono": 28, + "labstack/echo": 28, + "nushell/nushell": 28, + "prometheus/prometheus": 28, + "psf/black": 29, + "sharkdp/bat": 28, + "spf13/cobra": 31, + "tokio-rs/axum": 28 + }, + "after_per_repo_limit_20": { + "Textualize/rich": 19, + "colinhacks/zod": 20, + "honojs/hono": 13, + "labstack/echo": 17, + "nushell/nushell": 20, + "prometheus/prometheus": 20, + "psf/black": 20, + "sharkdp/bat": 18, + "spf13/cobra": 20, + "tokio-rs/axum": 20 + }, + "after_test_only_policy_and_repo_cap": { + "Textualize/rich": 19, + "colinhacks/zod": 20, + "honojs/hono": 13, + "labstack/echo": 17, + "nushell/nushell": 20, + "prometheus/prometheus": 20, + "psf/black": 20, + "sharkdp/bat": 18, + "spf13/cobra": 20, + "tokio-rs/axum": 20 + }, + "mined_with_corpus_gates": { + "Textualize/rich": 28, + "colinhacks/zod": 28, + "honojs/hono": 28, + "labstack/echo": 28, + "nushell/nushell": 28, + "prometheus/prometheus": 28, + "psf/black": 29, + "sharkdp/bat": 28, + "spf13/cobra": 31, + "tokio-rs/axum": 28 + } + }, + "name": "v2_edit2ripple", + "paths": { + "benchmark": "data/benchmark/v2_edit2ripple", + "corpus": "data/corpus/v2_edit2ripple" + }, + "repo_counts": { + "Textualize/rich": 19, + "colinhacks/zod": 20, + "honojs/hono": 13, + "labstack/echo": 17, + "nushell/nushell": 20, + "prometheus/prometheus": 20, + "psf/black": 20, + "sharkdp/bat": 18, + "spf13/cobra": 20, + "tokio-rs/axum": 20 + }, + "sample_count": 187, + "schema": "arb_extdev_v2", + "selection": { + "fatal_leakage_dropped_by_type": {}, + "order": "recency", + "per_repo_limit": 20, + "repo_cap": 20, + "repo_share": 0.25, + "test_only_dropped": 0, + "test_only_ratio": 0.23529411764705882 + }, + "task_counts": { + "edit2ripple": 187 + }, + "task_type": "edit2ripple" +} diff --git a/bench/arb/extdev/data/benchmark/v2_edit2ripple/samples.jsonl b/bench/arb/extdev/data/benchmark/v2_edit2ripple/samples.jsonl new file mode 100644 index 0000000..7d35985 --- /dev/null +++ b/bench/arb/extdev/data/benchmark/v2_edit2ripple/samples.jsonl @@ -0,0 +1,187 @@ +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "9993b5063da6c363bc8ebcf43792af90c1c23386", "candidate_corpus": {"base_commit": "9993b5063da6c363bc8ebcf43792af90c1c23386", "type": "repo_at_base_commit"}, "gold": {"files": ["storage/remote/write_otlp_handler_test.go"], "given_files": ["storage/remote/write_otlp_handler.go"]}, "id": "03e42dc4258ed9dd572fdcd5", "metadata": {"changed_files": ["storage/remote/write_otlp_handler.go", "storage/remote/write_otlp_handler_test.go"], "created_at": "2026-10-15T12:26:02Z", "fix_commit": "466be3beb37099c28804608966f894b0dbad9993", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 26, "deletions": 2, "is_test": true, "path": "storage/remote/write_otlp_handler_test.go", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"storage/remote/write_otlp_handler_test.go": ["otlp", "remote", "storage"]}}, "merged_at": "2026-10-15T19:27:31Z", "pr": 20030, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/20030"}, "query": {"anchor_diff": "@@ -286,7 +286,11 @@ func (app *otlpInstrumentedAppender) Append(ref storage.SeriesRef, ls labels.Lab\n \t\t\t// Not a partial error, return err.\n \t\t\treturn 0, err\n \t\t}\n-\t\tapp.outOfOrderExemplars.Add(float64(len(partialErr.ExemplarErrors)))\n+\t\tfor _, eErr := range partialErr.ExemplarErrors {\n+\t\t\tif errors.Is(eErr, storage.ErrOutOfOrderExemplar) {\n+\t\t\t\tapp.outOfOrderExemplars.Inc()\n+\t\t\t}\n+\t\t}\n \t\t// Hide the partial error as otlp converter does not handle it.\n \t}\n \tif opts.Metadata.IsEmpty() {", "anchor_file": "storage/remote/write_otlp_handler.go", "intent": "otlp: count only out-of-order exemplars in prometheus_api_otlp_out_of_order_exemplars_total\n\nSince Prometheus 3.10, `prometheus_api_otlp_out_of_order_exemplars_total` has counted every exemplar the storage rejects, whatever the reason, for example labels that are too long. Before that, it only counted out-of-order exemplars. This PR restores that.\n\n#### Release notes for end users (**ALL** commits must be considered).\n\n```release-notes\n[BUGFIX] OTLP: Count only out-of-order exemplars in `prometheus_api_otlp_out_of_order_exemplars_total`, not every rejected exemplar.\n```\n\notlp: count only out-of-order exemplars in the out-of-order counter"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "6e69e843b38d22ded60a13e0163f6326136f59fa", "candidate_corpus": {"base_commit": "6e69e843b38d22ded60a13e0163f6326136f59fa", "type": "repo_at_base_commit"}, "gold": {"files": ["model/textparse/openmetrics2parse_test.go"], "given_files": ["model/textparse/openmetrics2parse.go"]}, "id": "55d8093f9005df14b73675d7", "metadata": {"changed_files": ["model/textparse/openmetrics2parse.go", "model/textparse/openmetrics2parse_test.go"], "created_at": "2026-10-14T16:06:09Z", "fix_commit": "7d9f8fa7bffb7216d241c0ed1783802351bb56a8", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 86, "deletions": 13, "is_test": true, "path": "model/textparse/openmetrics2parse_test.go", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"model/textparse/openmetrics2parse_test.go": ["model", "openmetrics2parse", "textparse"]}}, "merged_at": "2026-10-16T06:57:45Z", "pr": 20020, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/20020"}, "query": {"anchor_diff": "@@ -93,6 +93,7 @@ type pendingEntry struct {\n \tseriesEnd int\n \tnameLen int\n \tinjectKey string\n+\tinjectVal float64\n \tval float64\n }\n \n@@ -382,11 +383,43 @@ func (p *openMetrics2Parser) Labels(l *labels.Labels) {\n // Exemplar writes the next exemplar of the current sample into e and returns\n // true. Returns false when all exemplars have been consumed.\n func (p *openMetrics2Parser) Exemplar(e *exemplar.Exemplar) bool {\n-\tif p.exemplarIdx >= len(p.exemplars) {\n+\tif len(p.exemplars) == 0 {\n \t\treturn false\n \t}\n-\tex := p.exemplars[p.exemplarIdx]\n-\tp.exemplarIdx++\n+\tvar ex om2Exemplar\n+\tif p.pendingIdx > 0 {\n+\t\tidx := p.pendingIdx - 1\n+\t\tpe := p.pending[idx]\n+\t\tif pe.injectKey != \"le\" {\n+\t\t\treturn false\n+\t\t}\n+\t\tupper := pe.injectVal\n+\t\thasLower := idx > 0 && p.pending[idx-1].injectKey == \"le\"\n+\t\tvar lower float64\n+\t\tif hasLower {\n+\t\t\tlower = p.pending[idx-1].injectVal\n+\t\t}\n+\t\tisPosInf := math.IsInf(upper, 1)\n+\t\tfound := false\n+\t\tfor p.exemplarIdx < len(p.exemplars) {\n+\t\t\tcand := p.exemplars[p.exemplarIdx]\n+\t\t\tp.exemplarIdx++\n+\t\t\tif (cand.val <= upper && (!hasLower || cand.val > lower)) || (isPosInf && math.IsNaN(cand.val)) {\n+\t\t\t\tex = cand\n+\t\t\t\tfound = true\n+\t\t\t\tbreak\n+\t\t\t}\n+\t\t}\n+\t\tif !found {\n+\t\t\treturn false\n+\t\t}\n+\t} else {\n+\t\tif p.exemplarIdx >= len(p.exemplars) {\n+\t\t\treturn false\n+\t\t}\n+\t\tex = p.exemplars[p.exemplarIdx]\n+\t\tp.exemplarIdx++\n+\t}\n \n \te.Value = ex.val\n \te.HasTs = true\n@@ -436,6 +469,7 @@ func (p *openMetrics2Parser) Next() (Entry, error) {\n \t// Drain pending composite-value entries.\n \tif p.pendingIdx < len(p.pending) {\n \t\tp.pendingIdx++\n+\t\tp.exemplarIdx = 0\n \t\treturn EntrySeries, nil\n \t}\n \tif len(p.pending) > 0 {\n@@ -1640,6 +1674,7 @@ func (p *openMetrics2Parser) appendPendingSeriesBytes(suffix, injectKey string,\n \t\tseriesEnd: len(p.seriesBuf),\n \t\tnameLen: nameLen,\n \t\tinjectKey: injectKey,\n+\t\tinjectVal: injectVal,\n \t\tval: val,\n \t}\n }", "anchor_file": "model/textparse/openmetrics2parse.go", "intent": "model/textparse: align OM 2.0 histogram exemplar parsing with protobuf\n\nWhen expanding an OpenMetrics 2.0 composite histogram into classic series (`_count`/`_gcount`, `_sum`/`_gsum`, `_bucket`), attach each exemplar on the line to the `_bucket` series with the smallest `le` threshold greater than or equal to the exemplar value (falling back to `+Inf` for `NaN`), rather than returning all exemplars on the first pending series (`_count`).\n\nWhen both a native histogram (or NHCB via `ConvertClassicHistogramsToNHCB`) and classic histogram series (`KeepClassicOnClassicAndNativeHistograms`) are emitted for the same sample line, return the exemplars on both the `EntryHistogram` and the matching classic `_bucket` `EntrySeries`, matching `ProtobufParser`.\n\n#### Which issue(s) does the PR fix:\n\nFixes #19869\nPart of #19745\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n```release-notes\n[BUGFIX] OpenMetrics 2.0: Attach histogram exemplars to matching classic `_bucket` series and preserve them when scraping both native and classic histograms.\n```\n\nmodel/textparse: align OM 2.0 histogram exemplar parsing with protobuf"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "ad230dcfd02f0f93d7c31349766240cedea97f44", "candidate_corpus": {"base_commit": "ad230dcfd02f0f93d7c31349766240cedea97f44", "type": "repo_at_base_commit"}, "gold": {"files": ["storage/remote/otlptranslator/prometheusremotewrite/helper_test.go"], "given_files": ["storage/remote/otlptranslator/prometheusremotewrite/helper.go"]}, "id": "5ee3fe1b1060dde5271337c5", "metadata": {"changed_files": ["storage/remote/otlptranslator/prometheusremotewrite/helper.go", "storage/remote/otlptranslator/prometheusremotewrite/helper_test.go"], "created_at": "2026-10-13T12:51:48Z", "fix_commit": "26b3ee772d031a380b4a82072f444e7256889aff", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 77, "deletions": 0, "is_test": true, "path": "storage/remote/otlptranslator/prometheusremotewrite/helper_test.go", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"storage/remote/otlptranslator/prometheusremotewrite/helper_test.go": ["otlptranslator", "prometheusremotewrite", "remote", "storage"]}}, "merged_at": "2026-10-16T08:06:42Z", "pr": 20004, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/20004"}, "query": {"anchor_diff": "@@ -385,12 +385,15 @@ func (c *PrometheusConverter) getPromExemplars(ctx context.Context, exemplars pm\n \t\t\treturn nil, fmt.Errorf(\"unsupported exemplar value type: %v\", ex.ValueType())\n \t\t}\n \n+\t\tvar hasTraceID, hasSpanID bool\n \t\tif traceID := ex.TraceID(); !traceID.IsEmpty() {\n+\t\t\thasTraceID = true\n \t\t\tval := hex.EncodeToString(traceID[:])\n \t\t\texemplarRunes += utf8.RuneCountInString(traceIDKey) + utf8.RuneCountInString(val)\n \t\t\tc.scratchBuilder.Add(traceIDKey, val)\n \t\t}\n \t\tif spanID := ex.SpanID(); !spanID.IsEmpty() {\n+\t\t\thasSpanID = true\n \t\t\tval := hex.EncodeToString(spanID[:])\n \t\t\texemplarRunes += utf8.RuneCountInString(spanIDKey) + utf8.RuneCountInString(val)\n \t\t\tc.scratchBuilder.Add(spanIDKey, val)\n@@ -398,6 +401,9 @@ func (c *PrometheusConverter) getPromExemplars(ctx context.Context, exemplars pm\n \n \t\tattrs := ex.FilteredAttributes()\n \t\tattrs.Range(func(key string, value pcommon.Value) bool {\n+\t\t\tif isOverriddenByTraceContext(key, hasTraceID, hasSpanID) {\n+\t\t\t\treturn true\n+\t\t\t}\n \t\t\texemplarRunes += utf8.RuneCountInString(key) + utf8.RuneCountInString(value.AsString())\n \t\t\treturn true\n \t\t})\n@@ -406,6 +412,9 @@ func (c *PrometheusConverter) getPromExemplars(ctx context.Context, exemplars pm\n \t\t// labels to exceed the max number of runes.\n \t\tif exemplarRunes <= maxExemplarRunes {\n \t\t\tattrs.Range(func(key string, value pcommon.Value) bool {\n+\t\t\t\tif isOverriddenByTraceContext(key, hasTraceID, hasSpanID) {\n+\t\t\t\t\treturn true\n+\t\t\t\t}\n \t\t\t\tc.scratchBuilder.Add(key, value.AsString())\n \t\t\t\treturn true\n \t\t\t})\n@@ -418,6 +427,14 @@ func (c *PrometheusConverter) getPromExemplars(ctx context.Context, exemplars pm\n \treturn outputExemplars, nil\n }\n \n+// isOverriddenByTraceContext reports whether the exemplar filtered attribute\n+// with the given key collides with a trace_id or span_id label that was set\n+// from the exemplar's trace context. Such attributes are dropped, as the trace\n+// context takes precedence.\n+func isOverriddenByTraceContext(key string, hasTraceID, hasSpanID bool) bool {\n+\treturn (hasTraceID && key == traceIDKey) || (hasSpanID && key == spanIDKey)\n+}\n+\n // findMinAndMaxTimestamps returns the minimum of minTimestamp and the earliest timestamp in metric and\n // the maximum of maxTimestamp and the latest timestamp in metric, respectively.\n func findMinAndMaxTimestamps(metric pmetric.Metric, minTimestamp, maxTimestamp pcommon.Timestamp) (pcommon.Timestamp, pcommon.Timestamp) {", "anchor_file": "storage/remote/otlptranslator/prometheusremotewrite/helper.go", "intent": "otlp: let exemplar trace context take precedence over filtered attributes\n\n#### Which issue(s) does the PR fix:\n\nFollow-up to #19896.\n\n#### Description\n\nWhen an OTLP exemplar has a trace ID or span ID, the OTLP translator adds them as `trace_id` and `span_id` exemplar labels, then appends every filtered attribute unchanged. If a filtered attribute is itself named `trace_id` or `span_id`, the exemplar ends up with duplicate label names. Before #19896 such an exemplar was stored and served with a duplicate JSON key from `/api/v1/query_exemplars`. Since #19896, TSDB rejects it as invalid, so the whole exemplar is dropped.\n\nSuch input is valid OTLP: the trace context lives in dedicated fields, so it does not collide with the filtered attributes inside OTLP itself. The [OpenTelemetry Prometheus compatibility specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/compatibility/prometheus_and_openmetrics.md#exemplars-1) requires that the `trace_id` and `span_id` labels \"MUST take precedence over labels from `filtered_attributes` in cases where there is a key collision\".\n\nThis PR drops a filtered attribute only when it collides with a label that was actually set from the trace context. If only a trace ID is present, a `span_id` filtered attribute is kept, and vice versa. Dropped attributes also no longer count towards the exemplar rune limit, so they cannot cause the remaining filtered attributes to be discarded.\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n```release-notes\n[BUGFIX] OTLP: Do not drop exemplars that have a `trace_id` or `span_id` filtered attribute in addition to a trace or span ID. The trace context now takes precedence over the colliding att\n...[truncated]"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "fd4847802c65256cb16e34f5e5c0e52a4b584cb6", "candidate_corpus": {"base_commit": "fd4847802c65256cb16e34f5e5c0e52a4b584cb6", "type": "repo_at_base_commit"}, "gold": {"files": ["promql/info.go", "promql/functions.go", "promql/engine_test.go"], "given_files": ["promql/engine.go"]}, "id": "301e0d9aae6cbec9a3802fca", "metadata": {"changed_files": ["docs/querying/operators.md", "promql/engine.go", "promql/engine_test.go", "promql/functions.go", "promql/info.go", "promql/promqltest/testdata/type_and_unit.test"], "created_at": "2026-10-10T18:14:15Z", "fix_commit": "2377dc1460206961d819ee3e2f6032b98a9e148c", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 2, "deletions": 1, "is_test": false, "path": "promql/info.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 2, "deletions": 2, "is_test": false, "path": "promql/functions.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 63, "deletions": 0, "is_test": true, "path": "promql/engine_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"promql/engine_test.go": ["engine", "promql"], "promql/functions.go": ["functions", "promql"], "promql/info.go": ["info", "promql"]}}, "merged_at": "2026-10-12T16:05:18Z", "pr": 19986, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "gold_diff_mentions_anchor_module", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/19986"}, "query": {"anchor_diff": "@@ -2151,6 +2151,9 @@ func (ev *evaluator) eval(ctx context.Context, expr parser.Expr) (parser.Value,\n \tcase *parser.AggregateExpr:\n \t\t// Grouping labels must be sorted (expected both by generateGroupingKey() and aggregation()).\n \t\tsortedGrouping := e.Grouping\n+\t\tif e.Without {\n+\t\t\tsortedGrouping = append([]string{model.MetricNameLabel, model.MetricTypeLabel, model.MetricUnitLabel}, sortedGrouping...)\n+\t\t}\n \t\tslices.Sort(sortedGrouping)\n \n \t\tif e.Op == parser.COUNT_VALUES {\n@@ -3302,7 +3305,7 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching *\n \t\t\tif matching.Card == parser.CardOneToMany {\n \t\t\t\toneSide = \"left\"\n \t\t\t}\n-\t\t\tmatchedLabels := rs.Metric.MatchLabels(matching.On, matching.MatchingLabels...)\n+\t\t\tmatchedLabels := matchLabels(rs.Metric, matching.On, matching.MatchingLabels...)\n \t\t\t// Make the error message consistent between runs by ordering the reported series.\n \t\t\tdupl1, dupl2 := rs.Metric.String(), duplSample.Metric.String()\n \t\t\tif dupl1 > dupl2 {\n@@ -3409,7 +3412,7 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching *\n \t\t\t\tcontinue\n \t\t\t}\n \t\t\trs = Sample{\n-\t\t\t\tMetric: ls.Metric.MatchLabels(matching.On, matching.MatchingLabels...),\n+\t\t\t\tMetric: matchLabels(ls.Metric, matching.On, matching.MatchingLabels...),\n \t\t\t\tF: *fill,\n \t\t\t}\n \t\t}\n@@ -3428,7 +3431,7 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching *\n \t\t\t\tcontinue // Already matched.\n \t\t\t}\n \t\t\tls := Sample{\n-\t\t\t\tMetric: rs.Metric.MatchLabels(matching.On, matching.MatchingLabels...),\n+\t\t\t\tMetric: matchLabels(rs.Metric, matching.On, matching.MatchingLabels...),\n \t\t\t\tF: *fill,\n \t\t\t}\n \n@@ -3439,6 +3442,13 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching *\n \treturn enh.Out, lastErr\n }\n \n+func matchLabels(metric labels.Labels, on bool, names ...string) labels.Labels {\n+\tif !on {\n+\t\tnames = append([]string{model.MetricNameLabel, model.MetricTypeLabel, model.MetricUnitLabel}, names...)\n+\t}\n+\treturn metric.MatchLabels(on, names...)\n+}\n+\n // resultMetric returns the metric for the given sample(s) based on the Vector\n // binary operation and the matching options.\n func resultMetric(lhs, rhs labels.Labels, op parser.ItemType, matching *parser.VectorMatching, dropMetricName bool, enh *EvalNodeHelper) labels.Labels {\n@@ -4512,7 +4522,8 @@ func generateGroupingLabels(enh *EvalNodeHelper, metric labels.Labels, without b\n \tswitch {\n \tcase without:\n \t\tenh.lb.Del(grouping...)\n-\t\tenh.lb.Del(labels.MetricName)\n+\t\t// Set empty name, type and unit labels to effectively remove those if specified.\n+\t\tschema.Metadata{}.SetToLabels(enh.lb)\n \t\treturn enh.lb.Labels()\n \tcase len(grouping) > 0:\n \t\tenh.lb.Keep(grouping...)", "anchor_file": "promql/engine.go", "intent": "promql: ignore and drop __type__ and __unit__ consistently across operators and functions\n\nFollow-up to #16228 and #18680 to ensure `__type__` and `__unit__` metadata labels are consistently ignored and dropped wherever `__name__` is ignored or dropped in PromQL:\n\n* Ignore and drop `__type__` and `__unit__` in `without(...)` aggregations (`generateGroupingKey` / `generateGroupingLabels`).\n* Exclude `__type__` and `__unit__` in `VectorBinop` label matching helpers when `!matching.On` (used for `fill` / `fill_left` / `fill_right` synthetic samples and duplicate-series error messages).\n* Drop all metadata labels via `schema.IsMetadataLabel` in `simpleHistogramFunc` (when delayed name removal is disabled), `createLabelsForAbsentFunction` (`absent()` / `absent_over_time()`), and `combineWithInfoVector` (`info()`).\n* Update `docs/querying/operators.md` to note that `__type__` and `__unit__` are dropped alongside `__name__`.\n\n#### Which issue(s) does the PR fix:\nPart of #16610\nRelated to #18635, #18680\n\n#### Release notes for end users (**ALL** commits must be considered).\n\n```release-notes\n[BUGFIX] PromQL: Consistently ignore and drop `__type__` and `__unit__` labels in `without` aggregations, `absent()`, `info()`, and binary operator fill matching.\n```\n\npromql: ignore and drop __type__ and __unit__ consistently across operators and functions\n\nAddress review comment: document schema.Metadata{}.SetToLabels in generateGroupingLabels"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "fd4847802c65256cb16e34f5e5c0e52a4b584cb6", "candidate_corpus": {"base_commit": "fd4847802c65256cb16e34f5e5c0e52a4b584cb6", "type": "repo_at_base_commit"}, "gold": {"files": ["promql/info.go", "promql/engine.go", "promql/engine_test.go"], "given_files": ["promql/functions.go"]}, "id": "9071d37bd51ebfc3684af8e1", "metadata": {"changed_files": ["docs/querying/operators.md", "promql/engine.go", "promql/engine_test.go", "promql/functions.go", "promql/info.go", "promql/promqltest/testdata/type_and_unit.test"], "created_at": "2026-10-10T18:14:15Z", "fix_commit": "2377dc1460206961d819ee3e2f6032b98a9e148c", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 2, "deletions": 1, "is_test": false, "path": "promql/info.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 15, "deletions": 4, "is_test": false, "path": "promql/engine.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 63, "deletions": 0, "is_test": true, "path": "promql/engine_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"promql/engine.go": ["promql"], "promql/engine_test.go": ["promql"], "promql/info.go": ["info", "promql"]}}, "merged_at": "2026-10-12T16:05:18Z", "pr": 19986, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "gold_diff_mentions_anchor_module", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/19986"}, "query": {"anchor_diff": "@@ -2192,7 +2192,7 @@ func simpleHistogramFunc(vectorVals []Vector, enh *EvalNodeHelper, f func(h *his\n \tfor _, el := range vectorVals[0] {\n \t\tif el.H != nil { // Process only histogram samples.\n \t\t\tif !enh.enableDelayedNameRemoval {\n-\t\t\t\tel.Metric = el.Metric.DropReserved(func(n string) bool { return n == labels.MetricName })\n+\t\t\t\tel.Metric = el.Metric.DropReserved(schema.IsMetadataLabel)\n \t\t\t}\n \t\t\tenh.Out = append(enh.Out, Sample{\n \t\t\t\tMetric: el.Metric,\n@@ -3011,7 +3011,7 @@ func createLabelsForAbsentFunction(expr parser.Expr) labels.Labels {\n \t// Note this gives arguably wrong behaviour for `absent(x{job=\"a\",job=\"a\",foo=\"bar\"})`.\n \thas := make(map[string]bool, len(lm))\n \tfor _, ma := range lm {\n-\t\tif ma.Name == labels.MetricName {\n+\t\tif schema.IsMetadataLabel(ma.Name) {\n \t\t\tcontinue\n \t\t}\n \t\tif ma.Type == labels.MatchEqual && !has[ma.Name] {", "anchor_file": "promql/functions.go", "intent": "promql: ignore and drop __type__ and __unit__ consistently across operators and functions\n\nFollow-up to #16228 and #18680 to ensure `__type__` and `__unit__` metadata labels are consistently ignored and dropped wherever `__name__` is ignored or dropped in PromQL:\n\n* Ignore and drop `__type__` and `__unit__` in `without(...)` aggregations (`generateGroupingKey` / `generateGroupingLabels`).\n* Exclude `__type__` and `__unit__` in `VectorBinop` label matching helpers when `!matching.On` (used for `fill` / `fill_left` / `fill_right` synthetic samples and duplicate-series error messages).\n* Drop all metadata labels via `schema.IsMetadataLabel` in `simpleHistogramFunc` (when delayed name removal is disabled), `createLabelsForAbsentFunction` (`absent()` / `absent_over_time()`), and `combineWithInfoVector` (`info()`).\n* Update `docs/querying/operators.md` to note that `__type__` and `__unit__` are dropped alongside `__name__`.\n\n#### Which issue(s) does the PR fix:\nPart of #16610\nRelated to #18635, #18680\n\n#### Release notes for end users (**ALL** commits must be considered).\n\n```release-notes\n[BUGFIX] PromQL: Consistently ignore and drop `__type__` and `__unit__` labels in `without` aggregations, `absent()`, `info()`, and binary operator fill matching.\n```\n\npromql: ignore and drop __type__ and __unit__ consistently across operators and functions\n\nAddress review comment: document schema.Metadata{}.SetToLabels in generateGroupingLabels"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "cc0aa45f6292160cbd501d4cd55d589d70629aa2", "candidate_corpus": {"base_commit": "cc0aa45f6292160cbd501d4cd55d589d70629aa2", "type": "repo_at_base_commit"}, "gold": {"files": ["promql/quantile_test.go"], "given_files": ["promql/quantile.go"]}, "id": "e00a053b45a106866dd4b1c6", "metadata": {"changed_files": ["promql/quantile.go", "promql/quantile_test.go"], "created_at": "2026-10-07T12:58:10Z", "fix_commit": "6e57ac2bac3b014f41eb3f77eb6e0adae4cf3d97", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 37, "deletions": 29, "is_test": true, "path": "promql/quantile_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"promql/quantile_test.go": ["promql", "quantile"]}}, "merged_at": "2026-10-12T11:36:04Z", "pr": 19963, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/19963"}, "query": {"anchor_diff": "@@ -531,6 +531,10 @@ func HistogramFraction(lower, upper float64, h *histogram.FloatHistogram, metric\n \n // BucketFraction is a version of HistogramFraction for classic histograms.\n func BucketFraction(lower, upper float64, buckets Buckets) float64 {\n+\tif len(buckets) == 0 {\n+\t\treturn math.NaN()\n+\t}\n+\n \tslices.SortFunc(buckets, func(a, b Bucket) int {\n \t\t// We don't expect the bucket boundary to be a NaN.\n \t\tif a.UpperBound < b.UpperBound {\n@@ -541,9 +545,6 @@ func BucketFraction(lower, upper float64, buckets Buckets) float64 {\n \t\t}\n \t\treturn 0\n \t})\n-\tif len(buckets) == 0 {\n-\t\treturn math.NaN()\n-\t}\n \tif !math.IsInf(buckets[len(buckets)-1].UpperBound, +1) {\n \t\treturn math.NaN()\n \t}", "anchor_file": "promql/quantile.go", "intent": "promql: simplify BucketFraction guard and tests\n\n#### Which issue(s) does the PR fix:\n\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n\n```release-notes\nNONE\n```\n\npromql: simplify BucketFraction guard and tests\n\npromql: clone bucket fraction test inputs"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "39c878f024238783f54631e3a5998e835d04db86", "candidate_corpus": {"base_commit": "39c878f024238783f54631e3a5998e835d04db86", "type": "repo_at_base_commit"}, "gold": {"files": ["promql/quantile_test.go"], "given_files": ["promql/quantile.go"]}, "id": "8eb3083873d6dd05807c025b", "metadata": {"changed_files": ["promql/quantile.go", "promql/quantile_test.go"], "created_at": "2026-10-06T23:31:09Z", "fix_commit": "cc0aa45f6292160cbd501d4cd55d589d70629aa2", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 36, "deletions": 0, "is_test": true, "path": "promql/quantile_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"promql/quantile_test.go": ["promql", "quantile"]}}, "merged_at": "2026-10-07T12:48:22Z", "pr": 19944, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/19944"}, "query": {"anchor_diff": "@@ -541,6 +541,9 @@ func BucketFraction(lower, upper float64, buckets Buckets) float64 {\n \t\t}\n \t\treturn 0\n \t})\n+\tif len(buckets) == 0 {\n+\t\treturn math.NaN()\n+\t}\n \tif !math.IsInf(buckets[len(buckets)-1].UpperBound, +1) {\n \t\treturn math.NaN()\n \t}", "anchor_file": "promql/quantile.go", "intent": "promql: handle empty input in BucketFraction\n\nFixes #19943\n\nThe exported `BucketFraction` helper panics with `index out of range [-1]` for a nil or empty bucket slice: it reads `buckets[len(buckets)-1]` to check for a `+Inf` last bucket before any length check. Return `NaN` for nil and empty slices, mirroring the `BucketQuantile` fix in #19927 (this is the follow-up @krajorama asked for there) and the native-histogram counterpart's zero-observation behavior. `NaN` is also what `BucketFraction` already returns for a nonempty slice whose last bucket is not `+Inf` and for a zero total count, so no new semantics are introduced.\n\nThis corrects an internal exported-helper contract; the current PromQL call site in `funcHistogramFraction` guards empty bucket lists before calling the helper, so no expression-evaluation failure is claimed.\n\nVerification:\n- The reporter's repro (`BucketFraction(0, 1, nil)`) panics on pristine `main` (39c878f) at `promql/quantile.go:544` and returns `NaN` with this change.\n- New `TestBucketFraction_EmptyBuckets` covers nil and non-nil empty slices across finite, reversed, infinite, and NaN bounds (all `NaN`), with a zero-count `+Inf` control; it panics with only the production change reverted and passes with it restored. A small `TestBucketFraction` control pins existing nonempty behavior (interpolated fraction, full range, reversed bounds).\n- Full `go test ./promql` passes; `gofmt` clean.\n\n```release-notes\nNONE\n```\n\nDeveloped with AI assistance.\n\npromql: handle empty input in BucketFraction"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "770ca8fb8f8e0765318910f2c43107261f9b875d", "candidate_corpus": {"base_commit": "770ca8fb8f8e0765318910f2c43107261f9b875d", "type": "repo_at_base_commit"}, "gold": {"files": ["tsdb/head.go", "tsdb/head_append.go", "tsdb/head_append_v2.go", "tsdb/head_wal.go"], "given_files": ["tsdb/db.go"]}, "id": "56733e6098911ed3dd04fc19", "metadata": {"changed_files": ["tsdb/db.go", "tsdb/db_test.go", "tsdb/head.go", "tsdb/head_append.go", "tsdb/head_append_v2.go", "tsdb/head_append_v2_test.go", "tsdb/head_test.go", "tsdb/head_wal.go"], "created_at": "2026-10-06T10:19:58Z", "fix_commit": "8c8c997d46cce44b84271273b7ab80d37c0d86de", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 56, "deletions": 7, "is_test": false, "path": "tsdb/head.go", "signals": ["same_component", "path_token_overlap", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}, {"additions": 2, "deletions": 0, "is_test": false, "path": "tsdb/head_append.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 2, "deletions": 0, "is_test": false, "path": "tsdb/head_append_v2.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 4, "deletions": 0, "is_test": false, "path": "tsdb/head_wal.go", "signals": ["same_component", "path_token_overlap"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"tsdb/head.go": ["head", "tsdb"], "tsdb/head_append.go": ["head", "tsdb"], "tsdb/head_append_v2.go": ["head", "tsdb"], "tsdb/head_wal.go": ["head", "tsdb", "wal"]}}, "merged_at": "2026-10-07T13:19:27Z", "pr": 19940, "ripple_relation": ["same_component", "path_token_overlap", "anchor_diff_mentions_gold_module", "shared_changed_symbol"], "source_pr": "https://github.com/prometheus/prometheus/pull/19940"}, "query": {"anchor_diff": "@@ -1879,6 +1879,11 @@ func (db *DB) compactHeadViewLocked(viewFactory headViewFactory, evict headSerie\n \treturn nil\n }\n \n+// CompactStaleHead writes stale series into blocks and evicts those that are still\n+// eligible for removal. Series whose exemplars still need replay remain in the head,\n+// but their persisted sample chunks are released if otherwise eligible for eviction.\n+// WAL replay may restore those samples after a restart until the global replay\n+// cutoff passes them.\n func (db *DB) CompactStaleHead() (err error) {\n \tdb.cmtx.Lock()\n \tdefer func() {\n@@ -1944,6 +1949,10 @@ func (db *DB) CompactStaleHead() (err error) {\n //\n // Series that received new samples after the ref list was collected are skipped during eviction\n // and remain in the head. They may be reconsidered during a subsequent compaction cycle.\n+// Series with exemplars at or after the global replay cutoff also remain in the head,\n+// until the cutoff passes the exemplar timestamps. Their persisted sample chunks are\n+// released if the series is otherwise eligible for eviction. WAL replay may restore\n+// those samples after a restart until the global replay cutoff passes them.\n //\n // This operation persists only in-order chunks. Series with non-empty out-of-order state at the\n // time of compaction are therefore skipped as well, since evicting them would orphan their", "anchor_file": "tsdb/db.go", "intent": "tsdb: preserve exemplars across compaction and restart\n\n#### Which issue(s) does the PR fix:\nCompaction can remove a series after its last sample is persisted, even when it still has a recent exemplar. Because exemplars are not stored in blocks, they depend on WAL replay for recovery. If WAL cleanup drops the series identity while retaining its exemplar record, the exemplar is lost on restart.\n\nThis change tracks each series’ latest accepted exemplar timestamp and preserves its identity until the exemplar falls below the replay cutoff. The protection applies to ordinary, selected, and stale compaction, and is restored when loading the WAL or a memory snapshot.\n\nSelected and stale compaction still release persisted sample chunks and their appenders when safe, while retaining the identity needed for exemplar recovery. Existing protections for concurrent appends and out-of-order samples remain in place.\n\nRegression tests cover compaction and repeated restarts, snapshot recovery, replay cutoff boundaries, zero and negative exemplar timestamps, and chunk reclamation for float and histogram samples.\n\n**One limitation remains**: after selected or stale compaction, WAL replay can restore already-persisted samples whose records remain eligible for replay. This PR reclaims their chunks in the running head but does not introduce a durable per-series compaction boundary.\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n\n```release-notes\n[BUGFIX] TSDB: Preserve series identities needed to recover exemplars after compaction and restart.\n\n```\n\n[tsdb]: preserve series with pending exemplars during ordinary compaction\n\n[tsdb]: distinguish absent exemplars from zero-valued timestamps during GC\n\n[tsdb]: preserve exempl\n...[truncated]"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "770ca8fb8f8e0765318910f2c43107261f9b875d", "candidate_corpus": {"base_commit": "770ca8fb8f8e0765318910f2c43107261f9b875d", "type": "repo_at_base_commit"}, "gold": {"files": ["tsdb/head.go", "tsdb/head_append.go", "tsdb/head_append_v2.go", "tsdb/db.go"], "given_files": ["tsdb/head_wal.go"]}, "id": "ced4fe34e6422cd716d54598", "metadata": {"changed_files": ["tsdb/db.go", "tsdb/db_test.go", "tsdb/head.go", "tsdb/head_append.go", "tsdb/head_append_v2.go", "tsdb/head_append_v2_test.go", "tsdb/head_test.go", "tsdb/head_wal.go"], "created_at": "2026-10-06T10:19:58Z", "fix_commit": "8c8c997d46cce44b84271273b7ab80d37c0d86de", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 56, "deletions": 7, "is_test": false, "path": "tsdb/head.go", "signals": ["same_component", "path_token_overlap", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}, {"additions": 2, "deletions": 0, "is_test": false, "path": "tsdb/head_append.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 2, "deletions": 0, "is_test": false, "path": "tsdb/head_append_v2.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 9, "deletions": 0, "is_test": false, "path": "tsdb/db.go", "signals": ["same_component", "path_token_overlap"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"tsdb/db.go": ["tsdb"], "tsdb/head.go": ["head", "tsdb"], "tsdb/head_append.go": ["head", "tsdb"], "tsdb/head_append_v2.go": ["head", "tsdb"]}}, "merged_at": "2026-10-07T13:19:27Z", "pr": 19940, "ripple_relation": ["same_component", "path_token_overlap", "anchor_diff_mentions_gold_module", "shared_changed_symbol"], "source_pr": "https://github.com/prometheus/prometheus/pull/19940"}, "query": {"anchor_diff": "@@ -147,6 +147,9 @@ func (h *Head) loadWAL(r *wlog.Reader, syms *labels.SymbolTable, multiRef map[ch\n \t\t\t// At the moment the only possible error here is out of order exemplars, which we shouldn't see when\n \t\t\t// replaying the WAL, so lets just log the error if it's not that type.\n \t\t\terr = h.exemplars.AddExemplar(ms.labels(), exemplar.Exemplar{Ts: e.T, Value: e.V, Labels: e.Labels})\n+\t\t\tif err == nil {\n+\t\t\t\tms.updateExemplarTimestamp(e.T)\n+\t\t\t}\n \t\t\tif err != nil && errors.Is(err, storage.ErrOutOfOrderExemplar) {\n \t\t\t\th.logger.Warn(\"Unexpected error when replaying WAL on exemplar record\", \"err\", err)\n \t\t\t}\n@@ -1923,6 +1926,7 @@ Outer:\n \t\t\t\t\tloopErr = fmt.Errorf(\"add exemplar: %w\", err)\n \t\t\t\t\tbreak Outer\n \t\t\t\t}\n+\t\t\t\tms.updateExemplarTimestamp(e.T)\n \t\t\t}\n \n \t\tdefault:", "anchor_file": "tsdb/head_wal.go", "intent": "tsdb: preserve exemplars across compaction and restart\n\n#### Which issue(s) does the PR fix:\nCompaction can remove a series after its last sample is persisted, even when it still has a recent exemplar. Because exemplars are not stored in blocks, they depend on WAL replay for recovery. If WAL cleanup drops the series identity while retaining its exemplar record, the exemplar is lost on restart.\n\nThis change tracks each series’ latest accepted exemplar timestamp and preserves its identity until the exemplar falls below the replay cutoff. The protection applies to ordinary, selected, and stale compaction, and is restored when loading the WAL or a memory snapshot.\n\nSelected and stale compaction still release persisted sample chunks and their appenders when safe, while retaining the identity needed for exemplar recovery. Existing protections for concurrent appends and out-of-order samples remain in place.\n\nRegression tests cover compaction and repeated restarts, snapshot recovery, replay cutoff boundaries, zero and negative exemplar timestamps, and chunk reclamation for float and histogram samples.\n\n**One limitation remains**: after selected or stale compaction, WAL replay can restore already-persisted samples whose records remain eligible for replay. This PR reclaims their chunks in the running head but does not introduce a durable per-series compaction boundary.\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n\n```release-notes\n[BUGFIX] TSDB: Preserve series identities needed to recover exemplars after compaction and restart.\n\n```\n\n[tsdb]: preserve series with pending exemplars during ordinary compaction\n\n[tsdb]: distinguish absent exemplars from zero-valued timestamps during GC\n\n[tsdb]: preserve exempl\n...[truncated]"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "770ca8fb8f8e0765318910f2c43107261f9b875d", "candidate_corpus": {"base_commit": "770ca8fb8f8e0765318910f2c43107261f9b875d", "type": "repo_at_base_commit"}, "gold": {"files": ["tsdb/index/index.go", "tsdb/index/index_test.go", "tsdb/head_test.go"], "given_files": ["tsdb/head_read.go"]}, "id": "9fe1fcb531e4af5e0297fda0", "metadata": {"changed_files": ["tsdb/head_read.go", "tsdb/head_test.go", "tsdb/index/index.go", "tsdb/index/index_test.go"], "created_at": "2026-10-06T00:01:31Z", "fix_commit": "92ac7f79130ef5c79f2c80e2164fce8ecb7de183", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 3, "deletions": 0, "is_test": false, "path": "tsdb/index/index.go", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 16, "deletions": 0, "is_test": true, "path": "tsdb/index/index_test.go", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 17, "deletions": 0, "is_test": true, "path": "tsdb/head_test.go", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"tsdb/head_test.go": ["head", "tsdb"], "tsdb/index/index.go": ["index", "tsdb"], "tsdb/index/index_test.go": ["tsdb"]}}, "merged_at": "2026-10-13T11:35:42Z", "pr": 19915, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/19915"}, "query": {"anchor_diff": "@@ -185,6 +185,9 @@ func (h *headIndexReader) ShardedPostings(p index.Postings, shardIndex, shardCou\n \tif notFoundSeriesCount > 0 {\n \t\th.head.logger.Debug(\"Looked up series not found\", \"count\", notFoundSeriesCount)\n \t}\n+\tif err := p.Err(); err != nil {\n+\t\treturn index.ErrPostings(fmt.Errorf(\"expand postings: %w\", err))\n+\t}\n \n \treturn index.NewListPostings(out)\n }", "anchor_file": "tsdb/head_read.go", "intent": "tsdb: return error from ShardedPostings if input errors\n\nPreserve input postings errors in head and block `ShardedPostings`.\nFailed inputs currently become list postings with a nil error.\n\nThis affects TSDB library callers using query sharding. Prometheus does not set `ShardCount`.\nTests cover empty and non-empty failing inputs.\n\nValidation:\n- `go test ./tsdb/... -count=1`\n- Sharded postings tests with `-race -count=5`.\n- `go build ./cmd/prometheus`\n- `make lint`\n\ncc @bboreham \n\n#### Which issue(s) does the PR fix:\nNone.\n\n#### Release notes for end users\n```release-notes\nNONE\n```\n\ntsdb: preserve ShardedPostings input errors"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "770ca8fb8f8e0765318910f2c43107261f9b875d", "candidate_corpus": {"base_commit": "770ca8fb8f8e0765318910f2c43107261f9b875d", "type": "repo_at_base_commit"}, "gold": {"files": ["tsdb/head_read.go", "tsdb/index/index_test.go", "tsdb/head_test.go"], "given_files": ["tsdb/index/index.go"]}, "id": "feac83842f0af678edf95820", "metadata": {"changed_files": ["tsdb/head_read.go", "tsdb/head_test.go", "tsdb/index/index.go", "tsdb/index/index_test.go"], "created_at": "2026-10-06T00:01:31Z", "fix_commit": "92ac7f79130ef5c79f2c80e2164fce8ecb7de183", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 3, "deletions": 0, "is_test": false, "path": "tsdb/head_read.go", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 16, "deletions": 0, "is_test": true, "path": "tsdb/index/index_test.go", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 17, "deletions": 0, "is_test": true, "path": "tsdb/head_test.go", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"tsdb/head_read.go": ["head", "tsdb"], "tsdb/head_test.go": ["head", "tsdb"], "tsdb/index/index_test.go": ["tsdb"]}}, "merged_at": "2026-10-13T11:35:42Z", "pr": 19915, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/19915"}, "query": {"anchor_diff": "@@ -1709,6 +1709,9 @@ func (r *Reader) ShardedPostings(p Postings, shardIndex, shardCount uint64) Post\n \n \t\tout = append(out, id)\n \t}\n+\tif err := p.Err(); err != nil {\n+\t\treturn ErrPostings(fmt.Errorf(\"expand postings: %w\", err))\n+\t}\n \n \treturn NewListPostings(out)\n }", "anchor_file": "tsdb/index/index.go", "intent": "tsdb: return error from ShardedPostings if input errors\n\nPreserve input postings errors in head and block `ShardedPostings`.\nFailed inputs currently become list postings with a nil error.\n\nThis affects TSDB library callers using query sharding. Prometheus does not set `ShardCount`.\nTests cover empty and non-empty failing inputs.\n\nValidation:\n- `go test ./tsdb/... -count=1`\n- Sharded postings tests with `-race -count=5`.\n- `go build ./cmd/prometheus`\n- `make lint`\n\ncc @bboreham \n\n#### Which issue(s) does the PR fix:\nNone.\n\n#### Release notes for end users\n```release-notes\nNONE\n```\n\ntsdb: preserve ShardedPostings input errors"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "d4467eede8e6d171c7ee06c0307a34878339a237", "candidate_corpus": {"base_commit": "d4467eede8e6d171c7ee06c0307a34878339a237", "type": "repo_at_base_commit"}, "gold": {"files": ["cmd/promtool/analyze.go", "cmd/promtool/query.go", "cmd/promtool/rules_test.go"], "given_files": ["cmd/promtool/rules.go"]}, "id": "163349708f705e80f5ce980b", "metadata": {"changed_files": ["cmd/promtool/analyze.go", "cmd/promtool/query.go", "cmd/promtool/rules.go", "cmd/promtool/rules_test.go", "go.mod", "go.sum"], "created_at": "2026-10-05T16:39:12Z", "fix_commit": "21fd457f2b67fe417e181817d814dba812471e9f", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "cmd/promtool/analyze.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 4, "deletions": 4, "is_test": false, "path": "cmd/promtool/query.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 2, "deletions": 2, "is_test": true, "path": "cmd/promtool/rules_test.go", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"cmd/promtool/analyze.go": ["cmd", "promtool"], "cmd/promtool/query.go": ["query", "cmd", "promtool"], "cmd/promtool/rules_test.go": ["cmd", "promtool", "rules"]}}, "merged_at": "2026-10-08T14:17:11Z", "pr": 19913, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/19913"}, "query": {"anchor_diff": "@@ -34,7 +34,7 @@ import (\n const maxSamplesInMemory = 5000\n \n type queryRangeAPI interface {\n-\tQueryRange(ctx context.Context, query string, r v1.Range, opts ...v1.Option) (model.Value, v1.Warnings, error)\n+\tQueryRange(ctx context.Context, query string, r v1.Range, opts ...v1.Option) (model.Value, v1.Warnings, v1.Infos, error)\n }\n \n type ruleImporter struct {\n@@ -115,7 +115,7 @@ func (importer *ruleImporter) importRule(ctx context.Context, ruleExpr, ruleName\n \t\tif end.Before(startWithAlignment) {\n \t\t\tbreak\n \t\t}\n-\t\tval, warnings, err := importer.apiClient.QueryRange(ctx,\n+\t\tval, warnings, infos, err := importer.apiClient.QueryRange(ctx,\n \t\t\truleExpr,\n \t\t\tv1.Range{\n \t\t\t\tStart: startWithAlignment,\n@@ -129,6 +129,9 @@ func (importer *ruleImporter) importRule(ctx context.Context, ruleExpr, ruleName\n \t\tif warnings != nil {\n \t\t\timporter.logger.Warn(\"Range query returned warnings.\", \"warnings\", warnings)\n \t\t}\n+\t\tif infos != nil {\n+\t\t\timporter.logger.Info(\"Range query returned infos.\", \"infos\", infos)\n+\t\t}\n \n \t\t// To prevent races with compaction, a block writer only allows appending samples\n \t\t// that are at most half a block size older than the most recent sample appended so far.", "anchor_file": "cmd/promtool/rules.go", "intent": "Upgrade client_golang to 1.25.0\n\nTests v1.25.0 (final) of client_golang. The RC was validated in https://github.com/prometheus/prometheus/pull/19913/ with no issues found; this bumps the tree to the released tag.\n\n## Known effects (as I had to change promtool):\n* `client_golang`'s `Query`, `QueryRange`, `Series`, `LabelNames`, and `LabelValues` now return `Infos` annotations in addition to `Warnings` (client_golang#1963). `promtool` ignores infos for query commands (same as warnings); the rule importer logs them.\n* Minimum Go version required by `client_golang` is now 1.26 (client_golang#2138).\n\nAlso bumps `prometheus/common` to v0.72.0, `procfs` to v0.22.0 (transitive requirements of `client_golang` v1.25.0), and the `exp` module to the release commit.\n\n```release-notes\nNONE\n```\n\nUpgrade client_golang to 1.25.0-rc.0\n\nUpgrade client_golang to v1.25.0 final release"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "d4467eede8e6d171c7ee06c0307a34878339a237", "candidate_corpus": {"base_commit": "d4467eede8e6d171c7ee06c0307a34878339a237", "type": "repo_at_base_commit"}, "gold": {"files": ["cmd/promtool/analyze.go", "cmd/promtool/rules.go", "cmd/promtool/rules_test.go"], "given_files": ["cmd/promtool/query.go"]}, "id": "d43c9ae84e89729862d823e1", "metadata": {"changed_files": ["cmd/promtool/analyze.go", "cmd/promtool/query.go", "cmd/promtool/rules.go", "cmd/promtool/rules_test.go", "go.mod", "go.sum"], "created_at": "2026-10-05T16:39:12Z", "fix_commit": "21fd457f2b67fe417e181817d814dba812471e9f", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "cmd/promtool/analyze.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 5, "deletions": 2, "is_test": false, "path": "cmd/promtool/rules.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 2, "deletions": 2, "is_test": true, "path": "cmd/promtool/rules_test.go", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"cmd/promtool/analyze.go": ["cmd", "promtool"], "cmd/promtool/rules.go": ["cmd", "promtool"], "cmd/promtool/rules_test.go": ["cmd", "promtool"]}}, "merged_at": "2026-10-08T14:17:11Z", "pr": 19913, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/19913"}, "query": {"anchor_diff": "@@ -79,7 +79,7 @@ func QueryInstant(url *url.URL, roundTripper http.RoundTripper, headers map[stri\n \n \t// Run query against client.\n \tctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)\n-\tval, _, err := api.Query(ctx, query, eTime) // Ignoring warnings for now.\n+\tval, _, _, err := api.Query(ctx, query, eTime) // Ignoring warnings and infos for now.\n \tcancel()\n \tif err != nil {\n \t\treturn handleAPIError(err)\n@@ -134,7 +134,7 @@ func QueryRange(url *url.URL, roundTripper http.RoundTripper, headers map[string\n \t// Run query against client.\n \tr := v1.Range{Start: stime, End: etime, Step: step}\n \tctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)\n-\tval, _, err := api.QueryRange(ctx, query, r) // Ignoring warnings for now.\n+\tval, _, _, err := api.QueryRange(ctx, query, r) // Ignoring warnings and infos for now.\n \tcancel()\n \n \tif err != nil {\n@@ -161,7 +161,7 @@ func QuerySeries(url *url.URL, roundTripper http.RoundTripper, matchers []string\n \n \t// Run query against client.\n \tctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)\n-\tval, _, err := api.Series(ctx, matchers, stime, etime) // Ignoring warnings for now.\n+\tval, _, _, err := api.Series(ctx, matchers, stime, etime) // Ignoring warnings and infos for now.\n \tcancel()\n \n \tif err != nil {\n@@ -188,7 +188,7 @@ func QueryLabels(url *url.URL, roundTripper http.RoundTripper, matchers []string\n \n \t// Run query against client.\n \tctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)\n-\tval, warn, err := api.LabelValues(ctx, name, matchers, stime, etime)\n+\tval, warn, _, err := api.LabelValues(ctx, name, matchers, stime, etime)\n \tcancel()\n \n \tfor _, v := range warn {", "anchor_file": "cmd/promtool/query.go", "intent": "Upgrade client_golang to 1.25.0\n\nTests v1.25.0 (final) of client_golang. The RC was validated in https://github.com/prometheus/prometheus/pull/19913/ with no issues found; this bumps the tree to the released tag.\n\n## Known effects (as I had to change promtool):\n* `client_golang`'s `Query`, `QueryRange`, `Series`, `LabelNames`, and `LabelValues` now return `Infos` annotations in addition to `Warnings` (client_golang#1963). `promtool` ignores infos for query commands (same as warnings); the rule importer logs them.\n* Minimum Go version required by `client_golang` is now 1.26 (client_golang#2138).\n\nAlso bumps `prometheus/common` to v0.72.0, `procfs` to v0.22.0 (transitive requirements of `client_golang` v1.25.0), and the `exp` module to the release commit.\n\n```release-notes\nNONE\n```\n\nUpgrade client_golang to 1.25.0-rc.0\n\nUpgrade client_golang to v1.25.0 final release"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "961c9ba40923ca4d7adf4a7a9167e56d0406df83", "candidate_corpus": {"base_commit": "961c9ba40923ca4d7adf4a7a9167e56d0406df83", "type": "repo_at_base_commit"}, "gold": {"files": ["docs/querying/api.md", "web/api/v1/search_test.go", "scrape/scrape_test.go"], "given_files": ["web/api/v1/search.go"]}, "id": "5c8c294a7a5290aff29cc37a", "metadata": {"changed_files": ["docs/querying/api.md", "scrape/scrape_test.go", "web/api/v1/search.go", "web/api/v1/search_test.go"], "created_at": "2026-10-05T02:24:48Z", "fix_commit": "b2c301420f56e1498bec668b5bb9af7dc45773bf", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 4, "deletions": 0, "is_test": false, "path": "docs/querying/api.md", "signals": ["shared_changed_symbol"]}, {"additions": 21, "deletions": 0, "is_test": true, "path": "web/api/v1/search_test.go", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 4, "deletions": 0, "is_test": true, "path": "scrape/scrape_test.go", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"docs/querying/api.md": ["api"], "scrape/scrape_test.go": ["scrape"], "web/api/v1/search_test.go": ["search", "web"]}}, "merged_at": "2026-10-05T09:07:15Z", "pr": 19910, "ripple_relation": ["shared_changed_symbol", "path_token_overlap", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/19910"}, "query": {"anchor_diff": "@@ -421,6 +421,11 @@ func (api *API) buildMetricMetadataMap(ctx context.Context) map[string][]scrape.\n // belongs to. An exact match on the family name wins. Otherwise the last\n // suffix is stripped and the metadata is returned if the family type allows\n // that suffix.\n+//\n+// A family name that already ends with _total or _info is in the Prometheus\n+// text style, where the series has the family name, so it is not matched for\n+// the same suffix again: x_total_total is not a series of the x_total family.\n+// This follows isSeriesPartOfFamily in scrape/scrape.go.\n func metadataForMetric(metaMap map[string][]scrape.MetricMetadata, name string) (scrape.MetricMetadata, bool) {\n \tif mds := metaMap[name]; len(mds) > 0 {\n \t\treturn mds[0], true\n@@ -429,8 +434,12 @@ func metadataForMetric(metaMap map[string][]scrape.MetricMetadata, name string)\n \tif i < 0 {\n \t\treturn scrape.MetricMetadata{}, false\n \t}\n-\tfor _, md := range metaMap[name[:i]] {\n-\t\tif typeAllowsSuffix(md.Type, name[i:]) {\n+\tfamily, suffix := name[:i], name[i:]\n+\tif (suffix == \"_total\" || suffix == \"_info\") && strings.HasSuffix(family, suffix) {\n+\t\treturn scrape.MetricMetadata{}, false\n+\t}\n+\tfor _, md := range metaMap[family] {\n+\t\tif typeAllowsSuffix(md.Type, suffix) {\n \t\t\treturn md, true\n \t\t}\n \t}", "anchor_file": "web/api/v1/search.go", "intent": "web/api/v1: Fix for metadata enrichment on double suffixed _total and _info\n\n#### Which issue(s) does the PR fix:\n\nThis PR is a follow up to https://github.com/prometheus/prometheus/pull/19824 and fixes an issue where metrics with double `_total` or `_info` suffixes are incorrectly considered as part of the wrong series family.\n\nThis can result in incorrect metadata added to metrics via the experimental search API.\n\nPrior to this PR `metadataForMetric` strips the last suffix and matches it against the family name. So `requests_total_total` gets the metadata of a `requests_total` counter, and `build_info_info` gets the metadata of a `build_info` info metric.\n\nThis is inconsistent with how `isSeriesPartOfFamily` in `scrape/scrape.go` would treat the same metric name, which would not consider `requests_total_total` part of the `requests_total` family.\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n```release-notes\n[BUGFIX] API: Do not match metric family metadata for doubled _total and _info suffixes in experimental search API.\n```\n\nFix for double suffix"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "961c9ba40923ca4d7adf4a7a9167e56d0406df83", "candidate_corpus": {"base_commit": "961c9ba40923ca4d7adf4a7a9167e56d0406df83", "type": "repo_at_base_commit"}, "gold": {"files": ["model/labels/float.go", "model/textparse/openmetrics2parse_test.go"], "given_files": ["model/textparse/openmetrics2parse.go"]}, "id": "77dc86558f2e0c200c7a456a", "metadata": {"changed_files": ["model/labels/float.go", "model/labels/float_test.go", "model/textparse/openmetrics2parse.go", "model/textparse/openmetrics2parse_test.go"], "created_at": "2026-10-02T15:29:33Z", "fix_commit": "6d833873a7aad133d822e952235b7549cafc8719", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 27, "deletions": 5, "is_test": false, "path": "model/labels/float.go", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 130, "deletions": 27, "is_test": true, "path": "model/textparse/openmetrics2parse_test.go", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"model/labels/float.go": ["labels", "model"], "model/textparse/openmetrics2parse_test.go": ["model", "openmetrics2parse", "textparse"]}}, "merged_at": "2026-10-13T10:09:05Z", "pr": 19895, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/19895"}, "query": {"anchor_diff": "@@ -83,16 +83,25 @@ func (l *openMetrics2Lexer) Error(es string) {\n // pendingEntry holds a single exploded flat series to be drained from the\n // pending queue that is built when a composite value (summary or classic\n // histogram) is parsed.\n+//\n+// Labels are not constructed eagerly during Next() because warm scrape caches\n+// only inspect Series() bytes; Labels() reconstructs the label set lazily from\n+// p.seriesBuf[seriesStart:seriesEnd] and p.offsets on a cache miss.\n type pendingEntry struct {\n-\tseries []byte\n-\tlset labels.Labels\n-\tval float64\n-\tts *int64\n+\tseriesStart int\n+\tseriesEnd int\n+\tnameLen int\n+\tinjectKey string\n+\tval float64\n }\n \n-// om2Exemplar holds a fully parsed exemplar.\n+// om2Exemplar holds the byte-offset range into p.eOffsets and parsed scalar\n+// fields for a single exemplar so that Exemplar() can construct labels lazily.\n type om2Exemplar struct {\n-\te exemplar.Exemplar\n+\toffsetsStart int\n+\toffsetsEnd int\n+\tval float64\n+\tts int64\n }\n \n // openMetrics2Parser parses samples from a byte slice in the OpenMetrics 2.0\n@@ -139,7 +148,10 @@ type openMetrics2Parser struct {\n \tfh *histogram.FloatHistogram\n \n \t// Multiple exemplars per sample (OM 2.0 allows zero or more).\n+\t// eOffsets stores the flat [k1Start, k1End, v1Start, v1End, ...] byte\n+\t// offsets into l.b across all exemplars on the current line.\n \texemplars []om2Exemplar\n+\teOffsets []int\n \texemplarIdx int\n \n \t// Pending queue for composite values exploded into flat EntrySeries.\n@@ -148,14 +160,10 @@ type openMetrics2Parser struct {\n \tpending []pendingEntry\n \tpendingIdx int\n \n-\t// seriesBuf backs pendingEntry.series; reused across entries to avoid\n-\t// allocating one identity per entry.\n+\t// seriesBuf backs pendingEntry series bytes; reused across composite lines\n+\t// to avoid allocating one byte slice per exploded entry.\n \tseriesBuf []byte\n \n-\t// extraLabels holds the non-__name__ labels for the current composite line,\n-\t// reused across composite parses.\n-\textraLabels []labels.Label\n-\n \tenableTypeAndUnitLabels bool\n \tignoreNativeHistograms bool\n \n@@ -175,9 +183,11 @@ type openMetrics2Parser struct {\n // NewOpenMetrics2Parser returns a new parser for the OpenMetrics 2.0 text\n // format.\n func NewOpenMetrics2Parser(b []byte, st *labels.SymbolTable, opts ParserOptions) Parser {\n+\tbuilder := labels.NewScratchBuilderWithSymbolTable(st, 16)\n+\tbuilder.SetUnsafeAdd(true)\n \tp := &openMetrics2Parser{\n \t\tl: &openMetrics2Lexer{b: b},\n-\t\tbuilder: labels.NewScratchBuilderWithSymbolTable(st, 16),\n+\t\tbuilder: builder,\n \t\tenableTypeAndUnitLabels: opts.EnableTypeAndUnitLabels,\n \t\tignoreNativeHistograms: opts.IgnoreNativeHistograms,\n \t\tkeepClassicOnNativeHist: opts.KeepClassicOnClassicAndNativeHistograms,\n@@ -194,8 +204,10 @@ func (p *openMetrics2Parser) resetOnFamilyChange(name []byte) {\n \tif !bytes.Equal(name, p.curFamilyName) {\n \t\tp.mtype = model.MetricTypeUnknown\n \t\tp.unit = \"\"\n+\t\t// Only update curFamilyName when the family changes to avoid a pointer\n+\t\t// write barrier on every sample within the same family.\n+\t\tp.curFamilyName = name\n \t}\n-\tp.curFamilyName = name\n }\n \n // hasFamilyNameLabel reports whether the current sample's labelsinclude a label key matching\n@@ -214,11 +226,14 @@ func (p *openMetrics2Parser) hasFamilyNameLabel() bool {\n func (p *openMetrics2Parser) Series() ([]byte, *int64, float64) {\n \tif p.pendingIdx > 0 {\n \t\tpe := p.pending[p.pendingIdx-1]\n-\t\treturn pe.series, pe.ts, pe.val\n+\t\tseries := p.seriesBuf[pe.seriesStart:pe.seriesEnd:pe.seriesEnd]\n+\t\tif p.hasTS {\n+\t\t\treturn series, &p.ts, pe.val\n+\t\t}\n+\t\treturn series, nil, pe.val\n \t}\n \tif p.hasTS {\n-\t\tts := p.ts\n-\t\treturn p.series, &ts, p.val\n+\t\treturn p.series, &p.ts, p.val\n \t}\n \treturn p.series, nil, p.val\n }\n@@ -227,8 +242,7 @@ func (p *openMetrics2Parser) Series() ([]byte, *int64, float64) {\n // and the native histogram value.\n func (p *openMetrics2Parser) Histogram() ([]byte, *int64, *histogram.Histogram, *histogram.FloatHistogram) {\n \tif p.hasTS {\n-\t\tts := p.ts\n-\t\treturn p.series, &ts, p.h, p.fh\n+\t\treturn p.series, &p.ts, p.h, p.fh\n \t}\n \treturn p.series, nil, p.h, p.fh\n }\n@@ -264,10 +278,53 @@ func (p *openMetrics2Parser) Comment() []byte {\n // Labels writes the labels of the current sample into l.\n func (p *openMetrics2Parser) Labels(l *labels.Labels) {\n \tif p.pendingIdx > 0 {\n-\t\t*l = p.pending[p.pendingIdx-1].lset\n+\t\tpe := p.pending[p.pendingIdx-1]\n+\t\t// p.builder has SetUnsafeAdd(true), so stringlabels and dedupelabels\n+\t\t// copy/intern strings inside Labels() and slicelabels clones inside Add().\n+\t\ts := yoloString(p.seriesBuf[pe.seriesStart:pe.seriesEnd])\n+\t\tp.builder.Reset()\n+\t\tmetricName := unreplace(s[:pe.nameLen])\n+\t\tm := schema.Metadata{\n+\t\t\tName: metricName,\n+\t\t\tType: p.mtype,\n+\t\t\tUnit: p.unit,\n+\t\t}\n+\t\tpos := pe.nameLen\n+\t\tif p.enableTypeAndUnitLabels {\n+\t\t\tif !m.IsTypeEmpty() {\n+\t\t\t\tpos += 1 + len(model.MetricTypeLabel) + 1 + len(p.mtype)\n+\t\t\t}\n+\t\t\tif p.unit != \"\" {\n+\t\t\t\tpos += 1 + len(model.MetricUnitLabel) + 1 + len(p.unit)\n+\t\t\t}\n+\t\t\tm.AddToLabels(&p.builder)\n+\t\t} else {\n+\t\t\tp.builder.Add(model.MetricNameLabel, metricName)\n+\t\t}\n+\t\tfor i := 2; i < len(p.offsets); i += 4 {\n+\t\t\tpos++ // skip SeparatorByte\n+\t\t\tkLen := p.offsets[i+1] - p.offsets[i]\n+\t\t\tlabel := unreplace(s[pos : pos+kLen])\n+\t\t\tpos += kLen + 1 // skip key and SeparatorByte\n+\t\t\tvLen := p.offsets[i+3] - p.offsets[i+2]\n+\t\t\tval := unreplace(s[pos : pos+vLen])\n+\t\t\tpos += vLen\n+\t\t\tif p.enableTypeAndUnitLabels && !m.IsEmptyFor(label) {\n+\t\t\t\tcontinue\n+\t\t\t}\n+\t\t\tp.builder.Add(label, val)\n+\t\t}\n+\t\tif pe.injectKey != \"\" {\n+\t\t\tpos += 1 + len(pe.injectKey) + 1 // skip SeparatorByte, injectKey, SeparatorByte\n+\t\t\tp.builder.Add(pe.injectKey, s[pos:])\n+\t\t}\n+\t\tp.builder.Sort()\n+\t\t*l = p.builder.Labels()\n \t\treturn\n \t}\n-\ts := string(p.series)\n+\t// p.builder has SetUnsafeAdd(true), so yoloString is safe across all labels\n+\t// implementations without allocating an intermediate string copy.\n+\ts := yoloString(p.series)\n \tp.builder.Reset()\n \tmetricName := unreplace(s[p.offsets[0]-p.start : p.offsets[1]-p.start])\n \tm := schema.Metadata{\n@@ -302,8 +359,26 @@ func (p *openMetrics2Parser) Exemplar(e *exemplar.Exemplar) bool {\n \tif p.exemplarIdx >= len(p.exemplars) {\n \t\treturn false\n \t}\n-\t*e = p.exemplars[p.exemplarIdx].e\n+\tex := p.exemplars[p.exemplarIdx]\n \tp.exemplarIdx++\n+\n+\te.Value = ex.val\n+\te.HasTs = true\n+\te.Ts = ex.ts\n...[truncated]", "anchor_file": "model/textparse/openmetrics2parse.go", "intent": "textparse [PERF]: defer OM2 composite and exemplar label allocations\n\nOptimize `openMetrics2Parser` CPU time and heap allocations across warm and cold scrape series caches:\n\n- Format exploded classic histogram (`_count`, `_sum`, `_bucket`) and summary (`_count`, `_sum`, quantile) series identity bytes directly into `p.seriesBuf` from `p.l.b` and `p.offsets` during `Next()`, and defer `labels.Labels` construction to `Labels()` so warm-cache scrapes do not sort or allocate `labels.Labels` on the heap.\n- Record exemplar label byte offsets into `p.eOffsets` during `Next()` and construct `e.Labels` lazily in `Exemplar()`.\n- Enable `SetUnsafeAdd(true)` on `p.builder` (matching `NewProtobufParser`) and pass `yoloString` slices in `Labels()` and `Exemplar()` to avoid intermediate string allocations before interning/cloning.\n- Return `&p.ts` from `Series()` and `Histogram()` instead of allocating a new `int64` on the heap per timestamped sample.\n- Skip redundant quote stripping and `utf8.Valid` checks on unquoted `tLName`/`tMName` tokens (already validated as non-empty ASCII by the lexer) and avoid redundant slice/pointer stores per sample.\n\n```\ngo test -count=6 -cpu=2 -benchmem -run='^$' -bench='^BenchmarkParseOM1VsOM2' ./model/textparse\n```\n\n```\ngoos: linux\ngoarch: amd64\npkg: github.com/prometheus/prometheus/model/textparse\ncpu: Intel(R) Xeon(R) CPU @ 2.20GHz\n │ before │ after │\n │ sec/op │ sec/op vs base │\nParseOM1VsOM2_AllTypes/parser=omtext-2 879.3µ ± 9% 856.2µ ± 1% ~ (p=0.589 n=6)\nParseOM1VsOM2_AllTypes/parser=omtext_with_nhcb-2 266.7µ ± 1% 269.9µ ± 2% ~ (p=0.093 n=6)\nPar\n...[truncated]"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "961c9ba40923ca4d7adf4a7a9167e56d0406df83", "candidate_corpus": {"base_commit": "961c9ba40923ca4d7adf4a7a9167e56d0406df83", "type": "repo_at_base_commit"}, "gold": {"files": ["model/textparse/openmetrics2parse.go", "model/textparse/openmetrics2parse_test.go"], "given_files": ["model/labels/float.go"]}, "id": "86b65fb9bcc1461c71fe335c", "metadata": {"changed_files": ["model/labels/float.go", "model/labels/float_test.go", "model/textparse/openmetrics2parse.go", "model/textparse/openmetrics2parse_test.go"], "created_at": "2026-10-02T15:29:33Z", "fix_commit": "6d833873a7aad133d822e952235b7549cafc8719", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 252, "deletions": 255, "is_test": false, "path": "model/textparse/openmetrics2parse.go", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 130, "deletions": 27, "is_test": true, "path": "model/textparse/openmetrics2parse_test.go", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"model/textparse/openmetrics2parse.go": ["model", "textparse"], "model/textparse/openmetrics2parse_test.go": ["model", "textparse"]}}, "merged_at": "2026-10-13T10:09:05Z", "pr": 19895, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/19895"}, "query": {"anchor_diff": "@@ -51,10 +51,32 @@ func FormatOpenMetricsFloat(f float64) string {\n \tbp := floatFormatBufPool.Get().(*[]byte)\n \tdefer floatFormatBufPool.Put(bp)\n \n-\t*bp = strconv.AppendFloat((*bp)[:0], f, 'g', -1, 64)\n-\tif bytes.ContainsAny(*bp, \"e.\") {\n-\t\treturn string(*bp)\n-\t}\n-\t*bp = append(*bp, '.', '0')\n+\t*bp = AppendOpenMetricsFloat((*bp)[:0], f)\n \treturn string(*bp)\n }\n+\n+// AppendOpenMetricsFloat appends the OpenMetrics float representation of f to\n+// dst and returns the extended buffer. Like FormatOpenMetricsFloat, it appends\n+// \".0\" if the formatted number would otherwise contain neither a \".\" nor an \"e\".\n+func AppendOpenMetricsFloat(dst []byte, f float64) []byte {\n+\tswitch {\n+\tcase f == 1:\n+\t\treturn append(dst, \"1.0\"...)\n+\tcase f == 0:\n+\t\treturn append(dst, \"0.0\"...)\n+\tcase f == -1:\n+\t\treturn append(dst, \"-1.0\"...)\n+\tcase math.IsNaN(f):\n+\t\treturn append(dst, \"NaN\"...)\n+\tcase math.IsInf(f, +1):\n+\t\treturn append(dst, \"+Inf\"...)\n+\tcase math.IsInf(f, -1):\n+\t\treturn append(dst, \"-Inf\"...)\n+\t}\n+\tstart := len(dst)\n+\tdst = strconv.AppendFloat(dst, f, 'g', -1, 64)\n+\tif !bytes.ContainsAny(dst[start:], \"e.\") {\n+\t\tdst = append(dst, '.', '0')\n+\t}\n+\treturn dst\n+}", "anchor_file": "model/labels/float.go", "intent": "textparse [PERF]: defer OM2 composite and exemplar label allocations\n\nOptimize `openMetrics2Parser` CPU time and heap allocations across warm and cold scrape series caches:\n\n- Format exploded classic histogram (`_count`, `_sum`, `_bucket`) and summary (`_count`, `_sum`, quantile) series identity bytes directly into `p.seriesBuf` from `p.l.b` and `p.offsets` during `Next()`, and defer `labels.Labels` construction to `Labels()` so warm-cache scrapes do not sort or allocate `labels.Labels` on the heap.\n- Record exemplar label byte offsets into `p.eOffsets` during `Next()` and construct `e.Labels` lazily in `Exemplar()`.\n- Enable `SetUnsafeAdd(true)` on `p.builder` (matching `NewProtobufParser`) and pass `yoloString` slices in `Labels()` and `Exemplar()` to avoid intermediate string allocations before interning/cloning.\n- Return `&p.ts` from `Series()` and `Histogram()` instead of allocating a new `int64` on the heap per timestamped sample.\n- Skip redundant quote stripping and `utf8.Valid` checks on unquoted `tLName`/`tMName` tokens (already validated as non-empty ASCII by the lexer) and avoid redundant slice/pointer stores per sample.\n\n```\ngo test -count=6 -cpu=2 -benchmem -run='^$' -bench='^BenchmarkParseOM1VsOM2' ./model/textparse\n```\n\n```\ngoos: linux\ngoarch: amd64\npkg: github.com/prometheus/prometheus/model/textparse\ncpu: Intel(R) Xeon(R) CPU @ 2.20GHz\n │ before │ after │\n │ sec/op │ sec/op vs base │\nParseOM1VsOM2_AllTypes/parser=omtext-2 879.3µ ± 9% 856.2µ ± 1% ~ (p=0.589 n=6)\nParseOM1VsOM2_AllTypes/parser=omtext_with_nhcb-2 266.7µ ± 1% 269.9µ ± 2% ~ (p=0.093 n=6)\nPar\n...[truncated]"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "fadf780dec7522178d84bcbb9ab6a78a82017a03", "candidate_corpus": {"base_commit": "fadf780dec7522178d84bcbb9ab6a78a82017a03", "type": "repo_at_base_commit"}, "gold": {"files": ["model/textparse/interface.go", "model/textparse/openmetrics2parse.go", "util/convertnhcb/convertnhcb.go", "model/textparse/interface_test.go"], "given_files": ["model/textparse/nhcbparse.go"]}, "id": "5cb828ba04fda3ff568a79b1", "metadata": {"changed_files": ["model/textparse/benchmark_test.go", "model/textparse/interface.go", "model/textparse/interface_test.go", "model/textparse/nhcbparse.go", "model/textparse/openmetrics2parse.go", "model/textparse/openmetrics2parse_test.go", "scrape/scrape_test.go", "util/convertnhcb/convertnhcb.go"], "created_at": "2026-10-01T14:31:36Z", "fix_commit": "5ba0e8648a4314e7d12adc6dbeb34b9d76cafab2", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 9, "deletions": 10, "is_test": false, "path": "model/textparse/interface.go", "signals": ["same_component", "path_token_overlap"]}, {"additions": 115, "deletions": 15, "is_test": false, "path": "model/textparse/openmetrics2parse.go", "signals": ["same_component", "path_token_overlap"]}, {"additions": 10, "deletions": 2, "is_test": false, "path": "util/convertnhcb/convertnhcb.go", "signals": ["shared_changed_symbol"]}, {"additions": 26, "deletions": 7, "is_test": true, "path": "model/textparse/interface_test.go", "signals": ["path_token_overlap", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"model/textparse/interface.go": ["model", "textparse"], "model/textparse/interface_test.go": ["model", "textparse"], "model/textparse/openmetrics2parse.go": ["model", "textparse"], "util/convertnhcb/convertnhcb.go": ["convertnhcb"]}}, "merged_at": "2026-10-02T14:40:10Z", "pr": 19880, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/19880"}, "query": {"anchor_diff": "@@ -368,19 +368,8 @@ func (p *NHCBParser) processNHCB() bool {\n \t}\n \th, fh, err := p.tempNHCB.Convert()\n \tif err == nil {\n-\t\tif h != nil {\n-\t\t\tif err := h.Validate(); err != nil {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t\tp.hNHCB = h\n-\t\t\tp.fhNHCB = nil\n-\t\t} else if fh != nil {\n-\t\t\tif err := fh.Validate(); err != nil {\n-\t\t\t\treturn false\n-\t\t\t}\n-\t\t\tp.hNHCB = nil\n-\t\t\tp.fhNHCB = fh\n-\t\t}\n+\t\tp.hNHCB = h\n+\t\tp.fhNHCB = fh\n \n \t\tlblsWithMetricName := p.tempLsetNHCB.DropReserved(func(n string) bool { return n == labels.MetricName })\n \t\t// Ensure we return `metric` instead of `metric{}` for name only", "anchor_file": "model/textparse/nhcbparse.go", "intent": "textparse [PERF]: convert OM2 classic histograms to NHCB directly without NHCBParser\n\nSupport `ConvertClassicHistogramsToNHCB` directly inside `openMetrics2Parser` instead of wrapping it with `NHCBParser` in `textparse.New`.\n\nBecause OpenMetrics 2.0 already groups classic histogram count, sum, and bucket values into a single composite line, `openMetrics2Parser` can populate `convertnhcb.TempHistogram` directly from the parsed composite fields without synthesizing intermediate `_count`, `_sum`, and `_bucket` series (and formatting `le` labels) only for `NHCBParser` to re-parse and re-collate them.\n\nWhen `ConvertClassicHistogramsToNHCB` is enabled:\n- Native histograms (`schema` field present) are still parsed as native histograms unless `IgnoreNativeHistograms` is also set, in which case their classic buckets are converted to NHCB.\n- If `KeepClassicHistograms` (`AlwaysScrapeClassicHistograms`) is also set, `openMetrics2Parser` returns `EntryHistogram` first and queues the flat classic series in `p.pending` for subsequent `Next()` calls, matching `NHCBParser` behavior.\n\nNote: the `+0.36%` to `+0.61%` (`+64 B/op`, `0 allocs/op`) change in `om2text` benchmarks without NHCB comes from embedding `convertnhcb.TempHistogram` in `openMetrics2Parser` (allocated once per `NewOpenMetrics2Parser` call).\n\n### Benchmarks\n\n```\ngo test -count=6 -benchmem -run=^$ -bench=\"BenchmarkParseOM1VsOM2\" ./model/textparse\n```\n\n```\ngoos: linux\ngoarch: amd64\npkg: github.com/prometheus/prometheus/model/textparse\ncpu: Intel(R) Xeon(R) CPU @ 2.20GHz\n │ before.txt │ after.txt │\n │ sec/op │ sec/op vs base │\nParseOM1VsOM2_AllTypes/parser=omte\n...[truncated]"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "fadf780dec7522178d84bcbb9ab6a78a82017a03", "candidate_corpus": {"base_commit": "fadf780dec7522178d84bcbb9ab6a78a82017a03", "type": "repo_at_base_commit"}, "gold": {"files": ["model/textparse/openmetrics2parse.go", "model/textparse/nhcbparse.go", "util/convertnhcb/convertnhcb.go", "model/textparse/interface_test.go"], "given_files": ["model/textparse/interface.go"]}, "id": "71dd0f0a218b44a81cf117fe", "metadata": {"changed_files": ["model/textparse/benchmark_test.go", "model/textparse/interface.go", "model/textparse/interface_test.go", "model/textparse/nhcbparse.go", "model/textparse/openmetrics2parse.go", "model/textparse/openmetrics2parse_test.go", "scrape/scrape_test.go", "util/convertnhcb/convertnhcb.go"], "created_at": "2026-10-01T14:31:36Z", "fix_commit": "5ba0e8648a4314e7d12adc6dbeb34b9d76cafab2", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 115, "deletions": 15, "is_test": false, "path": "model/textparse/openmetrics2parse.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 2, "deletions": 13, "is_test": false, "path": "model/textparse/nhcbparse.go", "signals": ["same_component", "path_token_overlap"]}, {"additions": 10, "deletions": 2, "is_test": false, "path": "util/convertnhcb/convertnhcb.go", "signals": ["shared_changed_symbol"]}, {"additions": 26, "deletions": 7, "is_test": true, "path": "model/textparse/interface_test.go", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"model/textparse/interface_test.go": ["interface", "model", "textparse"], "model/textparse/nhcbparse.go": ["model", "textparse"], "model/textparse/openmetrics2parse.go": ["model", "textparse"], "util/convertnhcb/convertnhcb.go": ["convertnhcb"]}}, "merged_at": "2026-10-02T14:40:10Z", "pr": 19880, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/19880"}, "query": {"anchor_diff": "@@ -159,10 +159,10 @@ type ParserOptions struct {\n \t// to native histogram custom buckets (NHCB) format.\n \tConvertClassicHistogramsToNHCB bool\n \n-\t// KeepClassicOnClassicAndNativeHistograms causes parser to output classic histogram\n-\t// that is also present as a native histogram. Supported by the protobuf\n-\t// parser and by the OpenMetrics 2.0 parser (where both representations\n-\t// can appear in a single composite value).\n+\t// KeepClassicOnClassicAndNativeHistograms (always_scrape_classic_histograms in scrape\n+\t// config) causes the parser to also output classic histogram series when a histogram\n+\t// is present as both a native and classic histogram (in Protobuf or OpenMetrics 2.0),\n+\t// or when converting a classic histogram to NHCB via ConvertClassicHistogramsToNHCB.\n \tKeepClassicOnClassicAndNativeHistograms bool\n \n \t// OpenMetricsSkipSTSeries determines whether to skip `_created` timestamp series\n@@ -199,13 +199,12 @@ func New(b []byte, contentType string, st *labels.SymbolTable, opts ParserOption\n \tswitch mediaType {\n \tcase \"application/openmetrics-text\":\n \t\tif version == openMetrics2Version {\n-\t\t\tbaseParser = NewOpenMetrics2Parser(b, st, opts)\n-\t\t} else {\n-\t\t\tbaseParser = NewOpenMetricsParser(b, st, func(o *openMetricsParserOptions) {\n-\t\t\t\to.skipSTSeries = opts.OpenMetricsSkipSTSeries\n-\t\t\t\to.enableTypeAndUnitLabels = opts.EnableTypeAndUnitLabels\n-\t\t\t})\n+\t\t\treturn NewOpenMetrics2Parser(b, st, opts), err\n \t\t}\n+\t\tbaseParser = NewOpenMetricsParser(b, st, func(o *openMetricsParserOptions) {\n+\t\t\to.skipSTSeries = opts.OpenMetricsSkipSTSeries\n+\t\t\to.enableTypeAndUnitLabels = opts.EnableTypeAndUnitLabels\n+\t\t})\n \tcase \"application/vnd.google.protobuf\":\n \t\treturn NewProtobufParser(\n \t\t\tb,", "anchor_file": "model/textparse/interface.go", "intent": "textparse [PERF]: convert OM2 classic histograms to NHCB directly without NHCBParser\n\nSupport `ConvertClassicHistogramsToNHCB` directly inside `openMetrics2Parser` instead of wrapping it with `NHCBParser` in `textparse.New`.\n\nBecause OpenMetrics 2.0 already groups classic histogram count, sum, and bucket values into a single composite line, `openMetrics2Parser` can populate `convertnhcb.TempHistogram` directly from the parsed composite fields without synthesizing intermediate `_count`, `_sum`, and `_bucket` series (and formatting `le` labels) only for `NHCBParser` to re-parse and re-collate them.\n\nWhen `ConvertClassicHistogramsToNHCB` is enabled:\n- Native histograms (`schema` field present) are still parsed as native histograms unless `IgnoreNativeHistograms` is also set, in which case their classic buckets are converted to NHCB.\n- If `KeepClassicHistograms` (`AlwaysScrapeClassicHistograms`) is also set, `openMetrics2Parser` returns `EntryHistogram` first and queues the flat classic series in `p.pending` for subsequent `Next()` calls, matching `NHCBParser` behavior.\n\nNote: the `+0.36%` to `+0.61%` (`+64 B/op`, `0 allocs/op`) change in `om2text` benchmarks without NHCB comes from embedding `convertnhcb.TempHistogram` in `openMetrics2Parser` (allocated once per `NewOpenMetrics2Parser` call).\n\n### Benchmarks\n\n```\ngo test -count=6 -benchmem -run=^$ -bench=\"BenchmarkParseOM1VsOM2\" ./model/textparse\n```\n\n```\ngoos: linux\ngoarch: amd64\npkg: github.com/prometheus/prometheus/model/textparse\ncpu: Intel(R) Xeon(R) CPU @ 2.20GHz\n │ before.txt │ after.txt │\n │ sec/op │ sec/op vs base │\nParseOM1VsOM2_AllTypes/parser=omte\n...[truncated]"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "23b9aebefe8f295fe49c5be978c94bedfb7db70c", "candidate_corpus": {"base_commit": "23b9aebefe8f295fe49c5be978c94bedfb7db70c", "type": "repo_at_base_commit"}, "gold": {"files": ["util/stats/query_stats.go", "promql/engine_test.go"], "given_files": ["promql/engine.go"]}, "id": "ac867c71e7c387dbb0b485c6", "metadata": {"changed_files": ["promql/engine.go", "promql/engine_test.go", "util/stats/query_stats.go"], "created_at": "2026-09-30T09:01:25Z", "fix_commit": "d2266dcd4f690a20ed050ab0059d4de68ffa274a", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 6, "deletions": 4, "is_test": false, "path": "util/stats/query_stats.go", "signals": ["gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 149, "deletions": 96, "is_test": true, "path": "promql/engine_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"promql/engine_test.go": ["engine", "promql"]}}, "merged_at": "2026-10-15T08:49:16Z", "pr": 19873, "ripple_relation": ["gold_diff_mentions_anchor_module", "shared_changed_symbol", "path_token_overlap", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/19873"}, "query": {"anchor_diff": "@@ -2088,6 +2088,8 @@ func (ev *evaluator) evalSubquery(ctx context.Context, subq *parser.SubqueryExpr\n \t\tRange: outerRange,\n \t\tAtTimestamp: subq.Timestamp,\n \t}\n+\t// Merge underlying consumption, including nested subqueries. The outer\n+\t// range-vector function must not count the materialized results again.\n \tev.samplesStats.MergeTotalSamplesFromSubquery(childStats, consumer)\n \tev.samplesStats.MergeSamplesReadFromSubquery(childStats, consumer)\n \tmat := val.(Matrix)\n@@ -2439,7 +2441,11 @@ func (ev *evaluator) eval(ctx context.Context, expr parser.Expr) (parser.Value,\n \t\t\t\t// Make the function call.\n \t\t\t\toutVec, annos := call(vectorVals, inMatrix, e.Args, enh)\n \t\t\t\twarnings.Merge(annos)\n-\t\t\t\tev.samplesStats.IncrementSamplesAtStep(step, fullWindowCount)\n+\t\t\t\t// Subquery consumption was already merged in evalSubquery; its\n+\t\t\t\t// materialized points do not add underlying sample consumption.\n+\t\t\t\tif !matrixFromSubquery {\n+\t\t\t\t\tev.samplesStats.IncrementSamplesAtStep(step, fullWindowCount)\n+\t\t\t\t}\n \t\t\t\tif samplesReadCount > 0 {\n \t\t\t\t\tev.samplesStats.IncrementSamplesReadAtStep(step, samplesReadCount)\n \t\t\t\t}", "anchor_file": "promql/engine.go", "intent": "promql: do not count subquery materialized samples in total samples\n\nTotalSamples measures logical underlying sample consumption. Subqueries\nalready merge that consumption into the parent statistics, so counting\ntheir materialized output in the outer range-vector function mixes\nunderlying consumption with intermediate processing. Exclude those points,\nconsistent with gathering intermediate vectors without charging them again\nto TotalSamples.\n\n\n\n#### Which issue(s) does the PR fix:\n\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n\n```release-notes\n[BUGFIX] PromQL: do not count subquery materialized samples in total samples statistics\n```\n\npromql: exclude materialized subquery points from total sample consumption"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "23b9aebefe8f295fe49c5be978c94bedfb7db70c", "candidate_corpus": {"base_commit": "23b9aebefe8f295fe49c5be978c94bedfb7db70c", "type": "repo_at_base_commit"}, "gold": {"files": ["promql/engine.go", "promql/engine_test.go"], "given_files": ["util/stats/query_stats.go"]}, "id": "f3d9de72fb9de488f3f08a3a", "metadata": {"changed_files": ["promql/engine.go", "promql/engine_test.go", "util/stats/query_stats.go"], "created_at": "2026-09-30T09:01:25Z", "fix_commit": "d2266dcd4f690a20ed050ab0059d4de68ffa274a", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 7, "deletions": 1, "is_test": false, "path": "promql/engine.go", "signals": ["anchor_diff_mentions_gold_module", "shared_changed_symbol"]}, {"additions": 149, "deletions": 96, "is_test": true, "path": "promql/engine_test.go", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"promql/engine.go": ["engine", "promql"], "promql/engine_test.go": ["engine", "promql"]}}, "merged_at": "2026-10-15T08:49:16Z", "pr": 19873, "ripple_relation": ["anchor_diff_mentions_gold_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/prometheus/prometheus/pull/19873"}, "query": {"anchor_diff": "@@ -264,12 +264,14 @@ type QuerySamples struct {\n \t// configured in the engine.\n \tPeakSamples int\n \n-\t// TotalSamples represents the total number of samples loaded while\n-\t// evaluating a query. For range-vector functions, each step counts the\n-\t// full window (points may be counted in multiple steps).\n+\t// TotalSamples represents logical underlying sample consumption while\n+\t// evaluating a query, using the existing histogram size weighting.\n+\t// Subqueries contribute their underlying consumption, not their materialized\n+\t// results. Overlapping evaluation windows may count the same samples repeatedly;\n+\t// this is not a count of unique samples or physical storage reads.\n \tTotalSamples int64\n \n-\t// TotalSamplesPerStep represents the total number of samples scanned\n+\t// TotalSamplesPerStep represents logical underlying sample consumption\n \t// per step while evaluating a query. Each step should be identical to the\n \t// TotalSamples when a step is run as an instant query, which means\n \t// we intentionally do not account for optimizations that happen inside the", "anchor_file": "util/stats/query_stats.go", "intent": "promql: do not count subquery materialized samples in total samples\n\nTotalSamples measures logical underlying sample consumption. Subqueries\nalready merge that consumption into the parent statistics, so counting\ntheir materialized output in the outer range-vector function mixes\nunderlying consumption with intermediate processing. Exclude those points,\nconsistent with gathering intermediate vectors without charging them again\nto TotalSamples.\n\n\n\n#### Which issue(s) does the PR fix:\n\n\n#### Release notes for end users (**ALL** commits must be considered).\n*Reviewers should verify clarity and quality.*\n\n\n```release-notes\n[BUGFIX] PromQL: do not count subquery materialized samples in total samples statistics\n```\n\npromql: exclude materialized subquery points from total sample consumption"}, "repo": "prometheus/prometheus", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "cfeea823ea175900fcdb2109c05eacfa354625bd", "candidate_corpus": {"base_commit": "cfeea823ea175900fcdb2109c05eacfa354625bd", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nu-command/src/system/run_external.rs", "crates/nu-mcp/src/evaluation.rs", "crates/nu-command/tests/commands/use_.rs"], "given_files": ["crates/nu-protocol/src/engine/engine_state.rs"]}, "id": "4c51179310658d759de82b6d", "metadata": {"changed_files": ["crates/nu-command/src/system/run_external.rs", "crates/nu-command/tests/commands/use_.rs", "crates/nu-mcp/src/evaluation.rs", "crates/nu-protocol/src/engine/engine_state.rs"], "created_at": "2026-10-16T16:47:01Z", "fix_commit": "190471268eccc24ae398de812c2667748f43f4be", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 7, "deletions": 14, "is_test": false, "path": "crates/nu-command/src/system/run_external.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 134, "deletions": 21, "is_test": false, "path": "crates/nu-mcp/src/evaluation.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 31, "deletions": 0, "is_test": true, "path": "crates/nu-command/tests/commands/use_.rs", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"crates/nu-command/src/system/run_external.rs": ["command", "crates"], "crates/nu-command/tests/commands/use_.rs": ["command", "commands", "crates", "use"], "crates/nu-mcp/src/evaluation.rs": ["crates", "mcp"]}}, "merged_at": "2026-10-16T17:09:30Z", "pr": 19270, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/nushell/nushell/pull/19270"}, "query": {"anchor_diff": "@@ -1071,21 +1071,61 @@ impl EngineState {\n }\n }\n \n+ /// Get the signature of a command as a call by `name` in the current scope sees it.\n+ ///\n+ /// The signature is named `name`, which can differ from the declared name: a module command\n+ /// declared as `foo bar` is `spam foo bar` after `use spam`, and an alias of an internal\n+ /// command carries a copy of the wrapped command's signature, so `alias st = str trim` would\n+ /// otherwise be named `str trim`.\n+ ///\n+ /// For an alias of an internal command, the positional parameters the alias already passes\n+ /// are dropped, because the parser matches a call's arguments to the parameters after them\n+ /// (see `parse_internal_call`): `alias home = cd ~` takes no `path`. Flags the alias passes\n+ /// stay listed.\n+ pub fn get_signature_in_scope(&self, name: String, decl_id: DeclId) -> Signature {\n+ let decl = self.get_decl(decl_id);\n+ let mut signature = self.get_signature(decl).update_from_command(decl);\n+ signature.name = name;\n+\n+ if let Some(alias) = decl.as_alias()\n+ && let Expr::Call(call) = &alias.wrapped_call.expr\n+ {\n+ // Arguments fill the required parameters first, then the optional ones, and\n+ // `...rest` takes any number, the order `Signature::get_positional` uses.\n+ let passed = call.positional_iter().count();\n+ let required = passed.min(signature.required_positional.len());\n+ signature.required_positional.drain(..required);\n+ let optional = (passed - required).min(signature.optional_positional.len());\n+ signature.optional_positional.drain(..optional);\n+ }\n+\n+ signature\n+ }\n+\n /// Get signatures of all commands within scope with their decl ids, sorted by name.\n ///\n- /// Each signature's `name` is the name the command is called by in the current scope, which\n- /// can differ from the declared name: a module command declared as `foo bar` is `spam foo bar`\n- /// after `use spam`, and an alias's signature is a copy of the command it wraps, so\n- /// `alias st = str trim` would otherwise be named `str trim`. A command in scope under several\n- /// names is listed once per name.\n+ /// Each signature is the one [`get_signature_in_scope`](Self::get_signature_in_scope) gives\n+ /// for the name. A command in scope under several names is listed once per name.\n+ ///\n+ /// Unless `include_hidden` is set, each name is resolved with `find_decl`, the lookup the\n+ /// parser uses, so the list holds the names a call can use, each with the command it runs.\n+ /// `get_decls_sorted(false)` isn't enough on its own: it checks each overlay against its own\n+ /// visibility, but a `hide` of a command from an earlier overlay is recorded in the overlay\n+ /// active at the time.\n pub fn get_signatures_and_declids(&self, include_hidden: bool) -> Vec<(Signature, DeclId)> {\n- self.get_decls_sorted(include_hidden)\n+ self.get_decls_sorted(true)\n .into_iter()\n+ .filter_map(|(name, id)| {\n+ let id = if include_hidden {\n+ id\n+ } else {\n+ self.find_decl(&name, &[])?\n+ };\n+ Some((name, id))\n+ })\n .map(|(name, id)| {\n- let decl = self.get_decl(id);\n- let mut signature = self.get_signature(decl).update_from_command(decl);\n- signature.name = String::from_utf8_lossy(&name).into_owned();\n- (signature, id)\n+ let name = String::from_utf8_lossy(&name).into_owned();\n+ (self.get_signature_in_scope(name, id), id)\n })\n .collect()\n }", "anchor_file": "crates/nu-protocol/src/engine/engine_state.rs", "intent": "fix(mcp): don't offer hidden commands, and leave out the arguments an alias already passes\n\n## Description\n\nFollow-up to #19262. Three problems remain in how the MCP server's `list_commands` and `command_help` tools, and the \"Did you mean\" hint for an unknown command, describe the commands in scope.\n\n- **Hidden commands are still offered.** `EngineState::get_decls_sorted(false)` checks each overlay only against that overlay's own visibility, but `hide` records the hide in the overlay that is active when it runs. After `alias st = str trim`, `overlay new x`, `hide st` (entered as separate lines), `st` can't be called, yet MCP lists it, `command_help st` documents it, and `' a ' | st` says \"Did you mean `st`?\". Module commands hidden the same way behave the same.\n- **`command_help` can describe the wrong command.** It searched the listed signatures for a matching name instead of resolving the name the way the parser does. When an overlay shadows `foo` and a later overlay hides that `foo`, a call to `foo` runs the original, but `command_help foo` documented the shadowing one. If a command was hidden and then imported again from a later overlay, `foo` ran but `command_help foo` said it didn't exist.\n- **An alias lists the arguments it already passes.** An alias of an internal command carries the wrapped command's full signature. `alias home = cd ~` was listed as `home {flags} (path)`, and `def \"foo bar\" [x: int] {}; alias fb = foo bar 1` as `fb `. The parser starts matching an alias call's arguments after the positionals the alias passes (`parse_internal_call`), so `home /tmp` and `fb 2` fail.\n\n## User-facing changes (Release notes)\n\n- The MCP server's `list_commands` and `command_help` tools, and the \"Did you mean\" hint for an unknown command, no longer offer a command\n...[truncated]"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "cfeea823ea175900fcdb2109c05eacfa354625bd", "candidate_corpus": {"base_commit": "cfeea823ea175900fcdb2109c05eacfa354625bd", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nu-protocol/src/engine/engine_state.rs", "crates/nu-mcp/src/evaluation.rs", "crates/nu-command/tests/commands/use_.rs"], "given_files": ["crates/nu-command/src/system/run_external.rs"]}, "id": "6f82a81bc4e6d3ad18203a26", "metadata": {"changed_files": ["crates/nu-command/src/system/run_external.rs", "crates/nu-command/tests/commands/use_.rs", "crates/nu-mcp/src/evaluation.rs", "crates/nu-protocol/src/engine/engine_state.rs"], "created_at": "2026-10-16T16:47:01Z", "fix_commit": "190471268eccc24ae398de812c2667748f43f4be", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 50, "deletions": 10, "is_test": false, "path": "crates/nu-protocol/src/engine/engine_state.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 134, "deletions": 21, "is_test": false, "path": "crates/nu-mcp/src/evaluation.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 31, "deletions": 0, "is_test": true, "path": "crates/nu-command/tests/commands/use_.rs", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"crates/nu-command/tests/commands/use_.rs": ["command", "commands", "crates"], "crates/nu-mcp/src/evaluation.rs": ["crates", "mcp"], "crates/nu-protocol/src/engine/engine_state.rs": ["engine_state", "crates"]}}, "merged_at": "2026-10-16T17:09:30Z", "pr": 19270, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/nushell/nushell/pull/19270"}, "query": {"anchor_diff": "@@ -629,7 +629,6 @@ pub fn command_not_found(\n \n if let Some((last, others)) = signatures\n .iter()\n- .map(|(sig, _)| sig)\n .filter(|sig| {\n let name = name.to_folded_case(); // do not allocate new strings in any()\n sig.name\n@@ -657,7 +656,7 @@ pub fn command_not_found(\n }\n \n // Try a fuzzy search on the names of all existing commands.\n- if let Some(cmd) = did_you_mean(signatures.iter().map(|(sig, _)| &sig.name), name) {\n+ if let Some(cmd) = did_you_mean(signatures.iter().map(|sig| &sig.name), name) {\n // The user is invoking an external command with the same name as a\n // built-in command. Remind them of this.\n if cmd == name {\n@@ -685,10 +684,7 @@ pub fn command_not_found(\n }\n }\n \n-fn suggestion_signatures(\n- engine_state: &EngineState,\n- command_span: Span,\n-) -> Vec<(Signature, DeclId)> {\n+fn suggestion_signatures(engine_state: &EngineState, command_span: Span) -> Vec {\n fn suggestion_span(engine_state: &EngineState, decl_id: DeclId) -> Option {\n let decl = engine_state.get_decl(decl_id);\n \n@@ -701,16 +697,13 @@ fn suggestion_signatures(\n engine_state\n .get_signatures_and_declids(false)\n .into_iter()\n+ // Avoid suggesting commands declared after this command. When the declaration order\n+ // can't be determined, keep the suggestion.\n .filter(|(_, decl_id)| {\n- if let Some(sugg_span) = suggestion_span(engine_state, *decl_id) {\n- // avoid suggesting commands declared after this command\n- sugg_span.start < command_span.start\n- } else {\n- // we can't determine declaration order,\n- // so default to keeping this suggestion\n- true\n- }\n+ suggestion_span(engine_state, *decl_id)\n+ .is_none_or(|sugg_span| sugg_span.start < command_span.start)\n })\n+ .map(|(sig, _)| sig)\n .collect()\n }", "anchor_file": "crates/nu-command/src/system/run_external.rs", "intent": "fix(mcp): don't offer hidden commands, and leave out the arguments an alias already passes\n\n## Description\n\nFollow-up to #19262. Three problems remain in how the MCP server's `list_commands` and `command_help` tools, and the \"Did you mean\" hint for an unknown command, describe the commands in scope.\n\n- **Hidden commands are still offered.** `EngineState::get_decls_sorted(false)` checks each overlay only against that overlay's own visibility, but `hide` records the hide in the overlay that is active when it runs. After `alias st = str trim`, `overlay new x`, `hide st` (entered as separate lines), `st` can't be called, yet MCP lists it, `command_help st` documents it, and `' a ' | st` says \"Did you mean `st`?\". Module commands hidden the same way behave the same.\n- **`command_help` can describe the wrong command.** It searched the listed signatures for a matching name instead of resolving the name the way the parser does. When an overlay shadows `foo` and a later overlay hides that `foo`, a call to `foo` runs the original, but `command_help foo` documented the shadowing one. If a command was hidden and then imported again from a later overlay, `foo` ran but `command_help foo` said it didn't exist.\n- **An alias lists the arguments it already passes.** An alias of an internal command carries the wrapped command's full signature. `alias home = cd ~` was listed as `home {flags} (path)`, and `def \"foo bar\" [x: int] {}; alias fb = foo bar 1` as `fb `. The parser starts matching an alias call's arguments after the positionals the alias passes (`parse_internal_call`), so `home /tmp` and `fb 2` fail.\n\n## User-facing changes (Release notes)\n\n- The MCP server's `list_commands` and `command_help` tools, and the \"Did you mean\" hint for an unknown command, no longer offer a command\n...[truncated]"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "430207e98eb564eb89ab4661268658ce3cf3c8f9", "candidate_corpus": {"base_commit": "430207e98eb564eb89ab4661268658ce3cf3c8f9", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nu-protocol/src/engine/sequence.rs"], "given_files": ["crates/nu-system/src/foreground.rs"]}, "id": "b545c7b9375c0622d87a5eaf", "metadata": {"changed_files": ["crates/nu-protocol/src/engine/sequence.rs", "crates/nu-system/src/foreground.rs"], "created_at": "2026-10-16T14:08:11Z", "fix_commit": "f97cd76f21e5d26df12fa3dcca7eae92305fd7a7", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "crates/nu-protocol/src/engine/sequence.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"crates/nu-protocol/src/engine/sequence.rs": ["crates"]}}, "merged_at": "2026-10-16T14:26:56Z", "pr": 19267, "ripple_relation": ["path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/nushell/nushell/pull/19267"}, "query": {"anchor_diff": "@@ -321,7 +321,7 @@ impl ForegroundGuard {\n \n return Ok(guard);\n } else if pcnt\n- .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |count| {\n+ .try_update(Ordering::SeqCst, Ordering::SeqCst, |count| {\n // Avoid a race condition: only increment if count is > 0\n if count > 0 { Some(count + 1) } else { None }\n })", "anchor_file": "crates/nu-system/src/foreground.rs", "intent": "Rename fetch_update to try_update\n\n## Description\n\n`std::sync::atomic::Atomic::fetch_update` has been renamed to `try_update` with the former working as a [deprecated alias](https://github.com/rust-lang/rust/issues/135894) for the latter. This PR renames each mention of `fetch_update` with `try_update` in order to avoid displaying two warnings during each build.\n\n## User-facing changes (Release notes)\n\nn/a\n\n## Additional notes\n\nrename fetch_update to try_update"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "430207e98eb564eb89ab4661268658ce3cf3c8f9", "candidate_corpus": {"base_commit": "430207e98eb564eb89ab4661268658ce3cf3c8f9", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nu-system/src/foreground.rs"], "given_files": ["crates/nu-protocol/src/engine/sequence.rs"]}, "id": "c62049c2ecfe09d7dd0a80af", "metadata": {"changed_files": ["crates/nu-protocol/src/engine/sequence.rs", "crates/nu-system/src/foreground.rs"], "created_at": "2026-10-16T14:08:11Z", "fix_commit": "f97cd76f21e5d26df12fa3dcca7eae92305fd7a7", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "crates/nu-system/src/foreground.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"crates/nu-system/src/foreground.rs": ["crates"]}}, "merged_at": "2026-10-16T14:26:56Z", "pr": 19267, "ripple_relation": ["path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/nushell/nushell/pull/19267"}, "query": {"anchor_diff": "@@ -15,7 +15,7 @@ impl Sequence {\n // We're only not using `fetch_add` so that we can check for overflow, as wrapping with the\n // identifier would lead to a serious bug - however unlikely that is.\n self.0\n- .fetch_update(Relaxed, Relaxed, |current| current.checked_add(1))\n+ .try_update(Relaxed, Relaxed, |current| current.checked_add(1))\n .map_err(|_| ShellError::NushellFailedHelp {\n msg: \"an accumulator for identifiers overflowed\".into(),\n help: format!(\"see {}\", std::panic::Location::caller()),", "anchor_file": "crates/nu-protocol/src/engine/sequence.rs", "intent": "Rename fetch_update to try_update\n\n## Description\n\n`std::sync::atomic::Atomic::fetch_update` has been renamed to `try_update` with the former working as a [deprecated alias](https://github.com/rust-lang/rust/issues/135894) for the latter. This PR renames each mention of `fetch_update` with `try_update` in order to avoid displaying two warnings during each build.\n\n## User-facing changes (Release notes)\n\nn/a\n\n## Additional notes\n\nrename fetch_update to try_update"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "07b01e2f376c0b2a84522720ebf3e5e4eeff7674", "candidate_corpus": {"base_commit": "07b01e2f376c0b2a84522720ebf3e5e4eeff7674", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nu-command/tests/commands/help.rs", "tests/shell/mod.rs"], "given_files": ["crates/nu-engine/src/documentation.rs"]}, "id": "f5635f9e67b3564039d9dc4b", "metadata": {"changed_files": ["crates/nu-command/tests/commands/help.rs", "crates/nu-engine/src/documentation.rs", "tests/shell/mod.rs"], "created_at": "2026-10-16T12:12:58Z", "fix_commit": "6112446c3c409933c9a7338cd7d00258991b3be3", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 51, "deletions": 8, "is_test": true, "path": "crates/nu-command/tests/commands/help.rs", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 14, "deletions": 1, "is_test": true, "path": "tests/shell/mod.rs", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"crates/nu-command/tests/commands/help.rs": ["help", "command", "crates"]}}, "merged_at": "2026-10-16T12:47:23Z", "pr": 19261, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/nushell/nushell/pull/19261"}, "query": {"anchor_diff": "@@ -1,8 +1,8 @@\n use crate::eval_call;\n use fancy_regex::{Captures, Regex};\n use nu_protocol::{\n- Category, Config, IntoPipelineData, PipelineData, PositionalArg, Signature, Span, SpanId,\n- Spanned, SyntaxShape, Type, Value,\n+ Alias, Category, Config, IntoPipelineData, PipelineData, PositionalArg, Signature, Span,\n+ SpanId, Spanned, SyntaxShape, Type, Value,\n ast::{Argument, Call, Expr, Expression, RecordItem},\n debugger::WithoutDebug,\n engine::CommandType,\n@@ -145,18 +145,13 @@ fn nu_highlight_string(\n .unwrap_or_else(|| code_string.to_string())\n }\n \n-/// Apply code highlighting to code in a capture group\n-fn highlight_capture_group(\n- captures: &Captures<'_, str>,\n+/// Highlight a code snippet the way [`highlight_code`] highlights text between backticks\n+fn highlight_inline_code(\n+ content: &str,\n engine_state: &EngineState,\n stack: &mut Stack,\n head: Span,\n ) -> String {\n- let Some(content) = captures.get(1) else {\n- // this shouldn't happen\n- return String::new();\n- };\n-\n // Save current color config\n let config_old = stack.get_config(engine_state);\n let mut config = (*config_old).clone();\n@@ -179,7 +174,7 @@ fn highlight_capture_group(\n stack.config = Some(Arc::new(config));\n \n // Highlight and reject invalid syntax\n- let highlighted = try_nu_highlight(content.into(), true, engine_state, stack, head)\n+ let highlighted = try_nu_highlight(content, true, engine_state, stack, head)\n // // Make highlighted string italic\n .map(|text| {\n let resets = text.match_indices(RESET).count();\n@@ -197,7 +192,7 @@ fn highlight_capture_group(\n stack.config = Some(config_old);\n \n // Use fallback style if highlight failed/syntax was invalid\n- highlighted.unwrap_or_else(|| highlight_fallback(content.into()))\n+ highlighted.unwrap_or_else(|| highlight_fallback(content))\n }\n \n /// Apply fallback code style\n@@ -229,11 +224,19 @@ fn highlight_code<'a>(\n \";\n static RE: LazyLock = LazyLock::new(|| Regex::new(PATTERN).expect(\"valid regex\"));\n \n- let do_try_highlight =\n- |captures: &Captures<'_, str>| highlight_capture_group(captures, engine_state, stack, head);\n+ let do_try_highlight = |captures: &Captures<'_, str>| match captures.get(1) {\n+ Some(content) => highlight_inline_code(content.as_str(), engine_state, stack, head),\n+ // this shouldn't happen\n+ None => String::new(),\n+ };\n RE.replace_all(text, do_try_highlight)\n }\n \n+/// The source text an alias expands to, as written: `str trim` for `alias st = str trim`\n+fn alias_expansion<'a>(alias: &Alias, engine_state: &'a EngineState) -> Cow<'a, str> {\n+ String::from_utf8_lossy(engine_state.get_span_contents(alias.wrapped_call.span))\n+}\n+\n #[allow(clippy::too_many_arguments)]\n fn get_alias_documentation(\n long_desc: &mut String,\n@@ -260,13 +263,15 @@ fn get_alias_documentation(\n return;\n };\n \n- let alias_expansion =\n- String::from_utf8_lossy(engine_state.get_span_contents(alias.wrapped_call.span));\n-\n write!(\n long_desc,\n \"{help_section_name}Expansion{RESET}:\\n {}\",\n- nu_highlight_string(&alias_expansion, engine_state, stack, head)\n+ nu_highlight_string(\n+ &alias_expansion(alias, engine_state),\n+ engine_state,\n+ stack,\n+ head\n+ )\n )\n .expect(\"writing to a String is infallible\");\n }\n@@ -308,86 +313,119 @@ fn get_command_documentation(\n // - Subcommands are included violating module scoping\n // - https://github.com/nushell/nushell/issues/11447\n // - https://github.com/nushell/nushell/issues/11625\n- // - Duplicate entries may appear when a single declaration is visible under multiple names (e.g. script `main` rewritten to filename plus an alias).\n- // See https://github.com/nushell/nushell/issues/17719.\n+ let subcommand_prefix = format!(\"{cmd_name} \");\n+ // Every name in scope that lists a declaration as a subcommand, with the name to print and,\n+ // for an alias of a subcommand, the name of the subcommand it runs. A declaration can be\n+ // registered under several names (a script's `main bar` is also `script.nu bar`, #17719) and\n+ // only some of them may match, so every name is checked.\n+ let mut candidates: Vec<_> = engine_state\n+ .get_decls_sorted(false)\n+ .into_iter()\n+ .filter_map(|(overlay_name, decl_id)| {\n+ let decl = engine_state.get_decl(decl_id);\n+ let name = String::from_utf8_lossy(&overlay_name);\n+\n+ // Prefer the overlay name for display, falling back to the declared name: a module\n+ // command is registered as `spam foo bar` but documented under its bare name\n+ // `foo bar`. An alias of a subcommand (`alias st = str trim` under `help str`) is\n+ // listed under the name it's called by, and `wraps` keeps the subcommand's name so the\n+ // alias sorts right after it. That name comes from the wrapped declaration, not from\n+ // the alias's signature, which is a copy taken before a script's `main bar` was\n+ // renamed to `script.nu bar`.\n+ let (name_to_print, wraps) = if name.starts_with(&subcommand_prefix) {\n+ (name.into_owned(), None)\n+ } else if decl.name().starts_with(&subcommand_prefix) {\n+ (decl.name().to_owned(), None)\n+ } else {\n+ let Expr::Call(call) = &decl.as_alias()?.wrapped_call.expr else {\n+ return None;\n+ };\n+ let wrapped = engine_state\n+ .get_signature(engine_state.get_decl(call.decl_id))\n+ .name;\n+ if !wrapped.starts_with(&subcommand_prefix) {\n+ return None;\n+ }\n+ (name.into_owned(), Some(wrapped))\n+ };\n+\n+ // A hidden declaration can't be called, so it isn't listed. `find_decl` also rejects a\n+ // name that now resolves to another declaration.\n+ (engine_state.find_decl(&overlay_name, &[]) == Some(decl_id)).then_some((\n+ decl_id,\n+ name_to_print,\n+ wraps,\n+ ))\n+ })\n+ .collect();\n+ // A declaration that matches under one of its own names is listed under that name, not as an\n+ // alias of the subcommand it runs: a script's `alias \"main baz\" = main bar` is registered as\n+ // both `main baz` and `script.nu baz`, and is listed as `script.nu baz`. The sort is stable,\n+ // so within each group the names stay in alphabetical order and the first one wins.\n+ candidates.sort_by_key(|(_, _, wraps)| wraps.is_some());\n+\n let mut subcommands = vec![];\n- // track which declarations we've already added to `subcommands`\n+ // Declarations already added to `subcommands`, so each one is listed once.\n let mut seen = HashSet::new();\n- let subcommand_prefix = format!(\"{cmd_name} \");\n- // A declaration can appear here under several overlay names (a script's `main bar` is also\n- // registered as `script.nu bar`), so every name is checked, not just one per declaration.\n- for (overlay_name, decl_id) in engine_state.get_decls_sorted(true) {\n+ for (decl_id, name_to_print, wraps) in candidates {\n let decl = engine_state.get_decl(decl_id);\n- let alias = decl.as_alias();\n- let sig = engine_state.get_signature(decl).update_from_command(decl);\n- let name = String::from_utf8_lossy(&overlay_name);\n-\n- // The declared name, used when no overlay name matches: a module command is registered as\n- // `spam foo bar` but documented under its bare signature name `foo bar`. An alias reuses\n- // the signature of the command it wraps, so `sig.name` is not a name the alias answers to.\n- let canonical_name = alias.map_or(&sig.name, |alias| &alia\n...[truncated]", "anchor_file": "crates/nu-engine/src/documentation.rs", "intent": "fix(help): drop hidden subcommands and fix multi-line, backticked, and script alias entries\n\n## Description\n\nFollow-up to #19253, which lists an alias in `help ` under its own name, right after the subcommand it runs. Four cases are still wrong on main:\n\n- A hidden custom subcommand is still listed. #19253 only dropped hidden aliases.\n- An alias written over several lines splits its entry across lines.\n- With color on, backticks inside an alias's expansion confuse the highlighter. The inner backticks disappear and the outer ones stay.\n- A script's `alias mb = main bar` is missing from `script.nu --help`, though `mb` works inside the script.\n\nWith this PR, `help` leaves out a hidden subcommand of any kind, joins an alias's expansion onto one line and highlights it as a whole, and lists a script alias of a `main` subcommand right after that subcommand.\n\nEach example shows the Subcommands section of `help`. Before is main at 776da6de4 (which includes #19253), after is this branch. Color is stripped.\n\nA hidden custom subcommand was still listed. You can't call it, so it's left out now.\n\n```nushell\ndef foo [] {}; def \"foo bar\" [] {}; def \"foo qux\" [] {}; hide \"foo qux\"; help foo\n```\n\nBefore:\n\n```nushell\nSubcommands:\n foo bar (custom) -\n foo qux (custom) -\n```\n\nAfter:\n\n```nushell\nSubcommands:\n foo bar (custom) -\n```\n\nAn alias written over several lines split its entry across lines. The entry joins them now.\n\n```nushell\ndef foo [] {}; def \"foo bar\" [x] {}\nalias fm = foo bar (\n 'a'\n)\nhelp foo\n```\n\nBefore:\n\n```nushell\nSubcommands:\n foo bar (custom) -\n fm (alias) - Alias for `foo bar (\n 'a'\n)`\n```\n\nAfter:\n\n```nushell\nSubcommands:\n foo bar (custom) -\n fm (alias) - Alias for foo bar ( 'a' )\n```\n\nBackticks inside the expansion lost their place. The highlighter drop\n...[truncated]"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "92165027ce8c5ca7d443c633508b1ba52f6287b5", "candidate_corpus": {"base_commit": "92165027ce8c5ca7d443c633508b1ba52f6287b5", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nu_plugin_gstat/Cargo.toml", "crates/nu_plugin_gstat/src/nu/mod.rs"], "given_files": ["crates/nu_plugin_gstat/src/gstat.rs"]}, "id": "1003e0fa6bb65284450294eb", "metadata": {"changed_files": ["Cargo.lock", "crates/nu_plugin_gstat/Cargo.toml", "crates/nu_plugin_gstat/src/gstat.rs", "crates/nu_plugin_gstat/src/nu/mod.rs"], "created_at": "2026-10-14T11:18:54Z", "fix_commit": "4b60dee2f6be0b8bbb4db274d472e06f8d9e5681", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 7, "deletions": 1, "is_test": false, "path": "crates/nu_plugin_gstat/Cargo.toml", "signals": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"]}, {"additions": 8, "deletions": 0, "is_test": false, "path": "crates/nu_plugin_gstat/src/nu/mod.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"crates/nu_plugin_gstat/Cargo.toml": ["cargo", "crates", "gstat", "plugin"], "crates/nu_plugin_gstat/src/nu/mod.rs": ["crates", "gstat", "plugin"]}}, "merged_at": "2026-10-14T12:48:28Z", "pr": 19233, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"], "source_pr": "https://github.com/nushell/nushell/pull/19233"}, "query": {"anchor_diff": "@@ -86,12 +86,15 @@ impl GStat {\n return Ok(self.create_empty_git_status(span));\n };\n \n+ // Name the repo after its working directory. The git dir's parent only works for a plain\n+ // checkout: a linked worktree's git dir is `.git/worktrees/` and a submodule's is\n+ // `.git/modules/`. A bare repo has no working directory, so use the git dir itself.\n let repo_name = repo\n- .path()\n- .parent()\n- .and_then(|p| p.file_name())\n+ .workdir()\n+ .unwrap_or_else(|| repo.path())\n+ .file_name()\n .map(|p| p.to_string_lossy().to_string())\n- .unwrap_or_else(|| \"\".to_string());\n+ .unwrap_or_default();\n \n let tag = calculate_tag\n .then(|| nearest_tag(&repo))\n@@ -110,21 +113,21 @@ impl GStat {\n \n Ok(Value::record(\n record! {\n- \"idx_added_staged\" => Value::int(stats.idx_added_staged as i64, span),\n- \"idx_modified_staged\" => Value::int(stats.idx_modified_staged as i64, span),\n- \"idx_deleted_staged\" => Value::int(stats.idx_deleted_staged as i64, span),\n- \"idx_renamed\" => Value::int(stats.idx_renamed as i64, span),\n- \"idx_type_changed\" => Value::int(stats.idx_type_changed as i64, span),\n- \"wt_untracked\" => Value::int(stats.wt_untracked as i64, span),\n- \"wt_modified\" => Value::int(stats.wt_modified as i64, span),\n- \"wt_deleted\" => Value::int(stats.wt_deleted as i64, span),\n- \"wt_type_changed\" => Value::int(stats.wt_type_changed as i64, span),\n- \"wt_renamed\" => Value::int(stats.wt_renamed as i64, span),\n- \"ignored\" => Value::int(stats.ignored as i64, span),\n- \"conflicts\" => Value::int(stats.conflicts as i64, span),\n- \"ahead\" => Value::int(stats.ahead as i64, span),\n- \"behind\" => Value::int(stats.behind as i64, span),\n- \"stashes\" => Value::int(stats.stashes as i64, span),\n+ \"idx_added_staged\" => Value::int(stats.idx_added_staged, span),\n+ \"idx_modified_staged\" => Value::int(stats.idx_modified_staged, span),\n+ \"idx_deleted_staged\" => Value::int(stats.idx_deleted_staged, span),\n+ \"idx_renamed\" => Value::int(stats.idx_renamed, span),\n+ \"idx_type_changed\" => Value::int(stats.idx_type_changed, span),\n+ \"wt_untracked\" => Value::int(stats.wt_untracked, span),\n+ \"wt_modified\" => Value::int(stats.wt_modified, span),\n+ \"wt_deleted\" => Value::int(stats.wt_deleted, span),\n+ \"wt_type_changed\" => Value::int(stats.wt_type_changed, span),\n+ \"wt_renamed\" => Value::int(stats.wt_renamed, span),\n+ \"ignored\" => Value::int(stats.ignored, span),\n+ \"conflicts\" => Value::int(stats.conflicts, span),\n+ \"ahead\" => Value::int(stats.ahead, span),\n+ \"behind\" => Value::int(stats.behind, span),\n+ \"stashes\" => Value::int(stats.stashes, span),\n \"repo_name\" => Value::string(repo_name, span),\n \"tag\" => Value::string(tag, span),\n \"branch\" => Value::string(stats.branch, span),\n@@ -165,41 +168,47 @@ impl GStat {\n }\n \n /// Stats which the interpreter uses to populate the gist expression\n+///\n+/// The counts from the status list (`idx_*`, `wt_*`, `ignored` and `conflicts`) are -1 when\n+/// libgit2 cannot compute the status, for example for a split or sparse index or a bare\n+/// repository, so that an unknown status never reads as a clean tree.\n #[derive(Debug, PartialEq, Eq, Default, Clone)]\n pub struct Stats {\n /// Number of files to be added\n- pub idx_added_staged: u16,\n+ pub idx_added_staged: i64,\n /// Number of staged changes to files\n- pub idx_modified_staged: u16,\n+ pub idx_modified_staged: i64,\n /// Number of staged deletions\n- pub idx_deleted_staged: u16,\n+ pub idx_deleted_staged: i64,\n /// Number of renamed files\n- pub idx_renamed: u16,\n+ pub idx_renamed: i64,\n /// Index file type change\n- pub idx_type_changed: u16,\n+ pub idx_type_changed: i64,\n \n /// Number of untracked files which are new to the repository\n- pub wt_untracked: u16,\n+ pub wt_untracked: i64,\n /// Number of modified files which have not yet been staged\n- pub wt_modified: u16,\n+ pub wt_modified: i64,\n /// Number of deleted files\n- pub wt_deleted: u16,\n+ pub wt_deleted: i64,\n /// Working tree file type change\n- pub wt_type_changed: u16,\n- /// Working tree renamed\n- pub wt_renamed: u16,\n-\n- // Ignored files\n- pub ignored: u16,\n+ pub wt_type_changed: i64,\n+ /// Number of unstaged renames: a deleted tracked file paired with a similar untracked file,\n+ /// which are then not counted in `wt_deleted` and `wt_untracked`. A renamed file that was\n+ /// also edited counts in `wt_modified` too.\n+ pub wt_renamed: i64,\n+\n+ /// Number of ignored entries; an ignored directory counts once, without walking into it\n+ pub ignored: i64,\n /// Number of unresolved conflicts in the repository\n- pub conflicts: u16,\n+ pub conflicts: i64,\n \n /// Number of commits ahead of the upstream branch\n- pub ahead: u16,\n+ pub ahead: i64,\n /// Number of commits behind the upstream branch\n- pub behind: u16,\n+ pub behind: i64,\n /// Number of stashes on the current branch\n- pub stashes: u16,\n+ pub stashes: i64,\n /// The branch name or other stats of the HEAD pointer\n pub branch: String,\n /// The of the upstream branch\n@@ -222,9 +231,16 @@ impl Stats {\n \n opts.include_untracked(true)\n .recurse_untracked_dirs(true)\n- .renames_head_to_index(true);\n-\n- if let Ok(statuses) = repo.statuses(Some(&mut opts)) {\n+ .include_ignored(true)\n+ .renames_head_to_index(true)\n+ .renames_index_to_workdir(true);\n+\n+ // Rename detection reads untracked files, and one unreadable file fails the whole list.\n+ // Retry without it so the other counts survive.\n+ if let Ok(statuses) = repo.statuses(Some(&mut opts)).or_else(|_| {\n+ opts.renames_index_to_workdir(false);\n+ repo.statuses(Some(&mut opts))\n+ }) {\n for status in statuses.iter() {\n let flags = status.status();\n \n@@ -267,6 +283,26 @@ impl Stats {\n st.conflicts += 1;\n }\n }\n+ } else {\n+ // libgit2 cannot read every index (split or sparse indexes, a damaged file), and a\n+ // bare repository has no working tree. Report the counts as unknown instead of as a\n+ // clean tree.\n+ for count in [\n+ &mut st.idx_added_staged,\n+ &mut st.idx_modified_staged,\n+ &mut st.idx_deleted_staged,\n+ &mut st.idx_renamed,\n+ &mut st.idx_type_changed,\n+ &mut st.wt_untracked,\n+ &mut st.wt_modified,\n+ &mut st.wt_deleted,\n+ &mut st.wt_type_changed,\n+ &mut st.wt_renamed,\n+ &mut st.ignored,\n+ &mut st.conflicts,\n+ ] {\n+ *count = -1;\n+ }\n }\n \n let _ = repo.stash_foreach(|_, &_, &_| {\n@@ -281,6 +317,7 @@ impl Stats {\n ///\n /// If in detached head, grab the first few characters of the commit ID if possible, otherwise\n /// simply provide HEAD as the branch name. This is to mimic the behaviour of `git status`.\n+ /// A branch with no commits yet is named after the branch `HEAD` points to.\n fn read_branch(&mut self, repo: &Repository) {\n self.branch = match repo.head() {\n Ok(head) => {\n@@ -307,9 +344,19 @@ impl Stats {\n...[truncated]", "anchor_file": "crates/nu_plugin_gstat/src/gstat.rs", "intent": "fix(gstat): stop wrapping counts and reporting unreadable status as clean, fill `ignored` and `wt_renamed`, link libgit2 statically\n\n## Description\n\n`gstat` gave wrong answers in several situations, all from the plugin's own code rather than from libgit2. I compared it with `git status` on fixture repos (built with git 2.56) and confirmed each case on the 0.116 plugin.\n\n## User-facing changes (Release notes)\n\n- `gstat` no longer wraps its counts above 65,535. A repository with 70,000 untracked files used to report 4,464.\n- When `gstat` can't read a repository's status (a split or sparse index, a damaged index, or a bare repository), the status counts (`idx_*`, `wt_*`, `ignored`, `conflicts`) are now -1 instead of 0, so the repository no longer looks clean. The other fields are still filled.\n- `gstat` now fills `ignored` (an ignored directory counts once) and `wt_renamed`. A file renamed without `git mv` now counts as one `wt_renamed` instead of one `wt_deleted` plus one `wt_untracked`, and also as `wt_modified` if it was edited after the move.\n- In a repository with no commits yet, `branch` shows the branch `HEAD` points to instead of `master` or `HEAD`.\n- `repo_name` is now the name of the working directory in linked worktrees and submodules (it used to be `worktrees` or `modules`) and the repository's own directory name for bare repositories.\n- The gstat plugin starts faster on systems where it used to link a system libgit2, such as a `cargo install` on macOS with Homebrew's libgit2.\n\n\n## Additional notes\n\nReplacing git2 with gitoxide (`gix`) would make each call about 2x faster, but it adds 60 crates. I measured it separately and left it out of this PR.\n\nfix(gstat): stop wrapping counts and reporting unreadable status as clean, fill `ignored` and `wt_renamed`, link l\n...[truncated]"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "92165027ce8c5ca7d443c633508b1ba52f6287b5", "candidate_corpus": {"base_commit": "92165027ce8c5ca7d443c633508b1ba52f6287b5", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nu_plugin_gstat/Cargo.toml", "crates/nu_plugin_gstat/src/gstat.rs"], "given_files": ["crates/nu_plugin_gstat/src/nu/mod.rs"]}, "id": "feec217bce9035f5a168c4e8", "metadata": {"changed_files": ["Cargo.lock", "crates/nu_plugin_gstat/Cargo.toml", "crates/nu_plugin_gstat/src/gstat.rs", "crates/nu_plugin_gstat/src/nu/mod.rs"], "created_at": "2026-10-14T11:18:54Z", "fix_commit": "4b60dee2f6be0b8bbb4db274d472e06f8d9e5681", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 7, "deletions": 1, "is_test": false, "path": "crates/nu_plugin_gstat/Cargo.toml", "signals": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"]}, {"additions": 217, "deletions": 47, "is_test": false, "path": "crates/nu_plugin_gstat/src/gstat.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"crates/nu_plugin_gstat/Cargo.toml": ["cargo", "crates", "gstat", "plugin"], "crates/nu_plugin_gstat/src/gstat.rs": ["gstat", "crates", "plugin"]}}, "merged_at": "2026-10-14T12:48:28Z", "pr": 19233, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"], "source_pr": "https://github.com/nushell/nushell/pull/19233"}, "query": {"anchor_diff": "@@ -25,6 +25,14 @@ impl SimplePluginCommand for GStat {\n \"Get the git status of a repo\"\n }\n \n+ fn extra_description(&self) -> &str {\n+ \"Every count is -1 outside a git repository. Inside one, the status counts (idx_*, wt_*, \\\n+ignored and conflicts) are -1 when the status can't be read, for example with a split or sparse \\\n+index or in a bare repository. wt_renamed counts unstaged renames, a deleted file paired with a \\\n+similar untracked file, which then don't count as wt_deleted or wt_untracked; a renamed file \\\n+that was also edited counts in wt_modified too. An ignored directory counts once in ignored.\"\n+ }\n+\n fn signature(&self) -> Signature {\n Signature::build(PluginCommand::name(self))\n .switch(\"no-tag\", \"Disable git tag resolving.\", None)", "anchor_file": "crates/nu_plugin_gstat/src/nu/mod.rs", "intent": "fix(gstat): stop wrapping counts and reporting unreadable status as clean, fill `ignored` and `wt_renamed`, link libgit2 statically\n\n## Description\n\n`gstat` gave wrong answers in several situations, all from the plugin's own code rather than from libgit2. I compared it with `git status` on fixture repos (built with git 2.56) and confirmed each case on the 0.116 plugin.\n\n## User-facing changes (Release notes)\n\n- `gstat` no longer wraps its counts above 65,535. A repository with 70,000 untracked files used to report 4,464.\n- When `gstat` can't read a repository's status (a split or sparse index, a damaged index, or a bare repository), the status counts (`idx_*`, `wt_*`, `ignored`, `conflicts`) are now -1 instead of 0, so the repository no longer looks clean. The other fields are still filled.\n- `gstat` now fills `ignored` (an ignored directory counts once) and `wt_renamed`. A file renamed without `git mv` now counts as one `wt_renamed` instead of one `wt_deleted` plus one `wt_untracked`, and also as `wt_modified` if it was edited after the move.\n- In a repository with no commits yet, `branch` shows the branch `HEAD` points to instead of `master` or `HEAD`.\n- `repo_name` is now the name of the working directory in linked worktrees and submodules (it used to be `worktrees` or `modules`) and the repository's own directory name for bare repositories.\n- The gstat plugin starts faster on systems where it used to link a system libgit2, such as a `cargo install` on macOS with Homebrew's libgit2.\n\n\n## Additional notes\n\nReplacing git2 with gitoxide (`gix`) would make each call about 2x faster, but it adds 60 crates. I measured it separately and left it out of this PR.\n\nfix(gstat): stop wrapping counts and reporting unreadable status as clean, fill `ignored` and `wt_renamed`, link l\n...[truncated]"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "afc9a5d49f89418c5f1ca50b7b48865672fb24cc", "candidate_corpus": {"base_commit": "afc9a5d49f89418c5f1ca50b7b48865672fb24cc", "type": "repo_at_base_commit"}, "gold": {"files": ["tests/modules/mod.rs"], "given_files": ["crates/nu-parser/src/parse_module.rs"]}, "id": "099a1f8f90979c21520389f3", "metadata": {"changed_files": ["crates/nu-parser/src/parse_module.rs", "tests/modules/mod.rs"], "created_at": "2026-10-13T15:58:20Z", "fix_commit": "f5affecddc93241fc5055765713145d25f815689", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 28, "deletions": 0, "is_test": true, "path": "tests/modules/mod.rs", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"tests/modules/mod.rs": ["mod", "modules"]}}, "merged_at": "2026-10-14T21:16:02Z", "pr": 19228, "ripple_relation": ["shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/nushell/nushell/pull/19228"}, "query": {"anchor_diff": "@@ -666,44 +666,44 @@ pub fn parse_module_block(\n (block, module, module_comments)\n }\n \n+/// Returns true if any module reachable from `module_id` (through submodules or imports)\n+/// has changed on disk since it was parsed.\n+///\n+/// Each module is checked at most once per call: modules are commonly reachable through many\n+/// paths (e.g. a utility module imported by most siblings), and without the `seen` set the walk\n+/// re-reads the same files once per path, which is very slow where file opens are expensive.\n fn module_needs_reloading(working_set: &StateWorkingSet, module_id: ModuleId) -> bool {\n- let module = working_set.get_module(module_id);\n-\n- fn submodule_need_reloading(working_set: &StateWorkingSet, submodule_id: ModuleId) -> bool {\n- let submodule = working_set.get_module(submodule_id);\n- let submodule_changed = if let Some((file_path, file_id)) = &submodule.file {\n- let existing_contents = working_set.get_contents_of_file(*file_id);\n- let file_contents = file_path.read(working_set);\n-\n- if let (Some(existing), Some(new)) = (existing_contents, file_contents) {\n- existing != new\n- } else {\n- false\n- }\n- } else {\n- false\n+ /// Returns true if the module's file has changed on disk. Modules without a file, and files\n+ /// that can no longer be read, count as unchanged.\n+ fn file_changed(working_set: &StateWorkingSet, module_id: ModuleId) -> bool {\n+ let Some((file_path, file_id)) = &working_set.get_module(module_id).file else {\n+ return false;\n };\n-\n- if submodule_changed {\n- true\n- } else {\n- module_needs_reloading(working_set, submodule_id)\n- }\n+ matches!(\n+ (working_set.get_contents_of_file(*file_id), file_path.read(working_set)),\n+ (Some(existing), Some(new)) if existing != new\n+ )\n }\n \n- let export_submodule_changed = module\n- .submodules\n- .iter()\n- .any(|(_, submodule_id)| submodule_need_reloading(working_set, *submodule_id));\n-\n- if export_submodule_changed {\n- return true;\n+ /// Recursive step. A module already in `seen` is skipped: `any()` stops at the first change,\n+ /// so a module reached again has already been found unchanged.\n+ fn walk(\n+ working_set: &StateWorkingSet,\n+ module_id: ModuleId,\n+ seen: &mut HashSet,\n+ ) -> bool {\n+ let module = working_set.get_module(module_id);\n+ module\n+ .submodules\n+ .iter()\n+ .map(|(_, id)| *id)\n+ .chain(module.imported_modules.iter().copied())\n+ .any(|id| {\n+ seen.insert(id) && (file_changed(working_set, id) || walk(working_set, id, seen))\n+ })\n }\n \n- module\n- .imported_modules\n- .iter()\n- .any(|submodule_id| submodule_need_reloading(working_set, *submodule_id))\n+ walk(working_set, module_id, &mut HashSet::new())\n }\n \n fn parse_module_file(", "anchor_file": "crates/nu-parser/src/parse_module.rs", "intent": "Optimize module reloading check\n\nCheck each module once when deciding whether to reload a cached module\n\n## Description\n\nWhen a module that has already been parsed is imported again, `parse_module_file` calls `module_needs_reloading` to check whether any file in the module's tree has changed on disk. That walk recurses through `submodules` and `imported_modules` without tracking which modules it has visited, so a module reachable through several paths is re-read once per *path*.\n\nThat's common in practice: a `mod.nu` that `export use`s its sibling files, where most siblings also `use` a few shared helpers. In the repro from the issue, every extra `use nested` of a 9-file module re-reads its files ~133 times; with a real 22-file library it's ~412 reads per import. Linux mostly hides this because file opens are cheap, but on Windows it dominates parse time, and the LSP pays it on every keystroke.\n\nThis PR adds a `seen` set for the duration of the walk, so each reachable module's file is read at most once per check. Skipping an already-seen module is safe: `any()` short-circuits on the first change, so a module seen again has already been found unchanged. I also extracted the read-and-compare into a separate `module_file_changed` function.\n\nMeasured on Windows with the repro script from the issue (`nu -n repro.nu`):\n\n| importers | before | after |\n| --------: | -----: | ----: |\n| 1 | 34.9 ms | 28.4 ms |\n| 2 | 51.2 ms | 29.2 ms |\n| 5 | 97.5 ms | 32.4 ms |\n| 10 | 179.0 ms | 38.3 ms |\n\nPer extra importer: **16.0 ms → 1.1 ms**. In my real-world case (a 13-file module importing a 22-file library from most of its files), parsing on Windows went from ~3.1 s to the point where the LSP is responsive again.\n\n## User-facing changes (Release notes)\n\nImproved performance when the same\n...[truncated]"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "4faa823718cb642525dcccd4e55784ebff621711", "candidate_corpus": {"base_commit": "4faa823718cb642525dcccd4e55784ebff621711", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nu-command/src/filters/join.rs", "crates/nu-command/tests/commands/join.rs"], "given_files": ["crates/nu-command/src/conversions/into/duration.rs"]}, "id": "59150103e259e0aecd0b0ca6", "metadata": {"changed_files": ["crates/nu-command/src/conversions/into/duration.rs", "crates/nu-command/src/filters/join.rs", "crates/nu-command/tests/commands/join.rs"], "created_at": "2026-10-12T11:47:32Z", "fix_commit": "af58d1426bf7485fdecda04e46299fd9cdf3e6de", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 111, "deletions": 83, "is_test": false, "path": "crates/nu-command/src/filters/join.rs", "signals": ["path_token_overlap"]}, {"additions": 45, "deletions": 3, "is_test": true, "path": "crates/nu-command/tests/commands/join.rs", "signals": ["path_token_overlap", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"crates/nu-command/src/filters/join.rs": ["join", "command", "crates"], "crates/nu-command/tests/commands/join.rs": ["join", "command", "crates"]}}, "merged_at": "2026-10-13T12:51:31Z", "pr": 19219, "ripple_relation": ["path_token_overlap", "optional_test_ripple"], "source_pr": "https://github.com/nushell/nushell/pull/19219"}, "query": {"anchor_diff": "@@ -1,11 +1,10 @@\n-use itertools::Itertools;\n-use std::str::FromStr;\n-\n use fancy_regex::Regex;\n+use itertools::Itertools;\n use nu_cmd_base::input_handler::{CmdArgument, operate};\n use nu_engine::command_prelude::*;\n use nu_parser::{DURATION_UNIT_GROUPS, parse_unit_value};\n use nu_protocol::{SUPPORTED_DURATION_UNITS, Unit, ast::Expr};\n+use std::str::FromStr;\n use std::sync::LazyLock;\n \n const NS_PER_MS: i64 = 1_000_000;", "anchor_file": "crates/nu-command/src/conversions/into/duration.rs", "intent": "fix(join): error when a table has no rows with the join column\n\n## Description\n\n`join` accepted a join column that its tables don't have. Depending on the join type, it returned an empty list or rows padded with `null`:\n\n```nushell\n> [[a b]; [1 2] [3 4]] | join [[a c]; [1 3] [4 5]] d | to nuon\n[]\n> [[a b]; [1 2] [3 4]] | join --left [[a c]; [1 3] [4 5]] a z | to nuon\n[[a, b, a_, c]; [1, 2, null, null], [3, 4, null, null]]\n```\n\n`join_rows` returned early when the table it was iterating had no row with the key, and the lookup table built from the other side came out empty when that side lacked the key. Neither path reported anything.\n\n## User-facing changes (Release notes)\n\n`join` now raises a `column_not_found` error when the input table or the right table has rows but none of them contain the join column. Before, a misspelled column name silently produced an empty result or rows full of `null`. Empty tables and tables where only some rows lack the column behave as before.\n\n```nushell\nError: nu::shell::column_not_found\n\n × Cannot find column 'd'\n ╭─[source:1:1]\n 1 │ [[a b]; [1 2] [3 4]] | join [[a c]; [1 3] [4 5]] d\n · ──────────┬───────── ┬\n · │ ╰── column 'd' is missing in one or more values\n · ╰── value originates here\n ╰────\n help: If some rows have this column, try using 'd?' for optional access, or\n pre-fill using the `default` command\n```\n\n## Additional notes\n\ncloses https://github.com/nushell/nushell/issues/19215\n\nfix(join): error when a table has no rows with the join column\n\nreview fixes\n\nmerge main\n\nfmt\n\nremove double negative statements"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "af37214641d62d104523ce36eeaac6a6323a005a", "candidate_corpus": {"base_commit": "af37214641d62d104523ce36eeaac6a6323a005a", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nu-table/src/types/expanded.rs", "crates/nu-table/tests/constrains.rs", "crates/nu-command/tests/commands/table/display.rs"], "given_files": ["crates/nu-table/src/table.rs"]}, "id": "b02aa8c36af6d47404d1b417", "metadata": {"changed_files": ["crates/nu-command/tests/commands/table/display.rs", "crates/nu-table/src/table.rs", "crates/nu-table/src/types/expanded.rs", "crates/nu-table/tests/constrains.rs"], "created_at": "2026-10-11T13:28:27Z", "fix_commit": "e56aca9da6c068b6c6d33bbb70bd1da82b7fd483", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 62, "deletions": 18, "is_test": false, "path": "crates/nu-table/src/types/expanded.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 38, "deletions": 1, "is_test": true, "path": "crates/nu-table/tests/constrains.rs", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 67, "deletions": 0, "is_test": true, "path": "crates/nu-command/tests/commands/table/display.rs", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"crates/nu-command/tests/commands/table/display.rs": ["crates", "table"], "crates/nu-table/src/types/expanded.rs": ["expanded", "crates", "table"], "crates/nu-table/tests/constrains.rs": ["crates", "table"]}}, "merged_at": "2026-10-11T18:50:21Z", "pr": 19212, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/nushell/nushell/pull/19212"}, "query": {"anchor_diff": "@@ -166,12 +166,7 @@ impl NuTable {\n for i in 0..count {\n let col = self.count_cols + i;\n for row in 0..self.count_rows {\n- self.styles\n- .cfg\n- .set_alignment_horizontal(Entity::Cell(row, col), self.styles.alignments.data);\n- self.styles\n- .cfg\n- .set_color(Entity::Cell(row, col), ANSIBuf::default());\n+ self.reset_style((row, col));\n }\n }\n }\n@@ -332,7 +327,9 @@ impl NuTable {\n ///\n /// `trail` is true when the last planned column is the trailing `...` column.\n pub(crate) fn plan_column_widths(&self, termwidth: usize) -> Option<(Vec, bool)> {\n- let mut data = self.data.clone();\n+ // The planners read only the first row (header widths) and drop or add\n+ // columns on every row, so planning on a copy of row 0 gives the same widths.\n+ let mut data = vec![self.data.first()?.clone()];\n let widths =\n maybe_truncate_columns(&mut data, self.widths.clone(), &self.config, termwidth);\n if widths.needed.is_empty() {\n@@ -346,28 +343,33 @@ impl NuTable {\n NuRecordsValue::width(&self.data[row][col])\n }\n \n- /// Prefer keeping columns that already contain nested tables.\n+ /// Makes the columns that currently hold nested tables the width priorities.\n+ ///\n+ /// Expanded tables set no other priorities, so the list is rebuilt from\n+ /// `nested_cells` on every call: a column whose nested tables were all\n+ /// collapsed to text stops taking width from the columns that still have one.\n pub(crate) fn prefer_nested_table_columns(&mut self) {\n- if self.nested_cells.is_empty() {\n- return;\n- }\n+ // `nested_cells` is a HashSet, so sort the columns to keep the\n+ // priority order (and with it the column plan) the same on every run.\n+ let mut nested_cols: Vec = self.nested_cells.iter().map(|&(_, col)| col).collect();\n+ nested_cols.sort_unstable();\n+ nested_cols.dedup();\n \n- let mut cols = self.config.width_priority_columns.clone();\n- for &(_, col) in &self.nested_cells {\n- if !cols.contains(&col) {\n- cols.push(col);\n- }\n- }\n- self.set_width_priority_columns(&cols);\n+ self.set_width_priority_columns(&nested_cols);\n }\n \n pub(crate) fn recalculate_dimensions(&mut self) {\n table_recalculate_widths(self);\n- self.heights = self\n- .data\n- .iter()\n- .map(|row| row.iter().map(|cell| cell.count_lines()).max().unwrap_or(0))\n- .collect();\n+ table_recalculate_heights(self);\n+ }\n+\n+ /// Resets a cell to the default data alignment and color.\n+ pub(crate) fn reset_style(&mut self, pos: (usize, usize)) {\n+ let entity = Entity::Cell(pos.0, pos.1);\n+ self.styles\n+ .cfg\n+ .set_alignment_horizontal(entity, self.styles.alignments.data);\n+ self.styles.cfg.set_color(entity, ANSIBuf::default());\n }\n }\n \n@@ -395,6 +397,14 @@ fn table_recalculate_widths(t: &mut NuTable) {\n t.widths = build_width(&t.data, t.count_cols, t.count_rows, pad);\n }\n \n+fn table_recalculate_heights(t: &mut NuTable) {\n+ t.heights = t\n+ .data\n+ .iter()\n+ .map(|row| row.iter().map(|cell| cell.count_lines()).max().unwrap_or(0))\n+ .collect();\n+}\n+\n #[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash)]\n struct CellConfiguration {\n index: Value,\n@@ -545,13 +555,11 @@ fn table_truncate(t: &mut NuTable, termwidth: usize) -> Option\n if widths.trail {\n let col = widths.needed.len() - 1;\n for row in 0..t.count_rows {\n- t.styles\n- .cfg\n- .set_alignment_horizontal(Entity::Cell(row, col), t.styles.alignments.data);\n- t.styles\n- .cfg\n- .set_color(Entity::Cell(row, col), ANSIBuf::default());\n+ t.reset_style((row, col));\n }\n+\n+ // Columns hidden behind `...` no longer set the row heights.\n+ table_recalculate_heights(t);\n }\n \n Some(widths)\n@@ -866,6 +874,7 @@ fn width_ctrl_truncate(\n cfg,\n col,\n heights.len(),\n+ width,\n &ctrl.nested_cells,\n truncate,\n );\n@@ -876,6 +885,7 @@ fn width_ctrl_truncate(\n cfg,\n col,\n heights.len(),\n+ width,\n &ctrl.nested_cells,\n wrap,\n );\n@@ -899,6 +909,7 @@ fn width_ctrl_truncate(\n cfg,\n col,\n heights.len(),\n+ width,\n &ctrl.nested_cells,\n truncate,\n );\n@@ -920,40 +931,40 @@ fn width_ctrl_truncate(\n dims.set_widths(ctrl.width.needed);\n }\n \n+/// Applies `opt` (wrap or truncate) to the plain cells of column `col`.\n+///\n+/// Wrapping a pre-rendered nested table scrambles its borders, so nested cells\n+/// are not wrapped. A nested cell can still be wider than the column: `draw`\n+/// re-plans widths after `refit_nested_tables` ran, and the inner table cannot\n+/// always shrink to fit. papergrid then subtracts the cell width from the\n+/// column width and underflows (a panic in debug builds, a run-away padding\n+/// loop in release builds), so such a cell is cut to `width` line by line.\n fn apply_width_skipping_nested_tables(\n recs: &mut NuRecords,\n cfg: &mut ColoredConfig,\n col: usize,\n count_rows: usize,\n+ width: usize,\n nested_cells: &HashSet<(usize, usize)>,\n opt: O,\n ) where\n O: CellOption + Clone,\n {\n- let mut has_nested = false;\n- let mut has_plain = false;\n- for row in 0..count_rows {\n- if nested_cells.contains(&(row, col)) {\n- has_nested = true;\n- } else {\n- has_plain = true;\n- }\n- }\n-\n+ let has_nested = (0..count_rows).any(|row| nested_cells.contains(&(row, col)));\n if !has_nested {\n CellOption::::change(opt, recs, cfg, Entity::Column(col));\n return;\n }\n \n- if !has_plain {\n- return;\n- }\n-\n for row in 0..count_rows {\n+ let pos = Entity::Cell(row, col);\n if nested_cells.contains(&(row, col)) {\n- continue;\n+ // `Truncate` leaves cells that already fit untouched.\n...[truncated]", "anchor_file": "crates/nu-table/src/table.rs", "intent": "fix(table): stop `table --expand` hanging when a nested table is wider than its column\n\n## Description\n\n`open Cargo.toml | [ $in ] | table -e -w 183` on main grows memory until the OOM killer ends nu. A debug build panics instead.\n\n### Before, debug build of main:\n\n```nushell\n> open Cargo.toml | [ $in ] | table -e -w 183 | ignore\nError: × Main thread panicked.\n ├─▶ at .../papergrid-0.18.0/src/grid/peekable.rs:985:20\n ╰─▶ attempt to subtract with overflow\n```\n\nBefore, release build of main (0.116.2 at 251b39276): no output, RSS climbs about 390 MB a second (406 MB after 1 s, 2.35 GB after 6 s) until killed. After, release build of this branch: 0.02 s, 24 MB peak RSS.\n\n### After:\n\n```nushell\n> open Cargo.toml | [ $in ] | table -e -w 183\n╭───┬────────────┬─────────────┬────────────┬────────────┬──────────────┬────────────┬───────────────┬────────────┬────────────┬────────────┬───────────┬────────────┬────────────────╮\n│ # │ package │ test │ workspace │ lints │ dependencies │ target │ build-depende │ dev-depend │ features │ profile │ bin │ patch │ bench │\n│ │ │ │ │ │ │ │ ncies │ encies │ │ │ │ │ │\n├───┼────────────┼─────────────┼────────────┼────────────┼──────────────┼────────────┼───────────────┼────────────┼────────────┼────────────┼───────────┼────────────┼────────────────┤\n│ 0 │ {record 15 │ ╭───┬─────╮ │ {record 4 │ {record 1 │ {record 33 │ {record 2 │ {record 1 │ {record 12 │ {record 14 │ {record 3 │ [table 1 │ {record 1 │ ╭───┬────────╮ │\n│ │ fields} │ │ # │ ... │ │ fields} │ field} │ fields} │ fields} │ field} │ fields} │ fields} │ fi\n...[truncated]"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "af37214641d62d104523ce36eeaac6a6323a005a", "candidate_corpus": {"base_commit": "af37214641d62d104523ce36eeaac6a6323a005a", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nu-table/src/table.rs", "crates/nu-table/tests/constrains.rs", "crates/nu-command/tests/commands/table/display.rs"], "given_files": ["crates/nu-table/src/types/expanded.rs"]}, "id": "cb0a2c1010d3c1579f092833", "metadata": {"changed_files": ["crates/nu-command/tests/commands/table/display.rs", "crates/nu-table/src/table.rs", "crates/nu-table/src/types/expanded.rs", "crates/nu-table/tests/constrains.rs"], "created_at": "2026-10-11T13:28:27Z", "fix_commit": "e56aca9da6c068b6c6d33bbb70bd1da82b7fd483", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 107, "deletions": 46, "is_test": false, "path": "crates/nu-table/src/table.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 38, "deletions": 1, "is_test": true, "path": "crates/nu-table/tests/constrains.rs", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 67, "deletions": 0, "is_test": true, "path": "crates/nu-command/tests/commands/table/display.rs", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"crates/nu-command/tests/commands/table/display.rs": ["crates", "table"], "crates/nu-table/src/table.rs": ["table", "crates"], "crates/nu-table/tests/constrains.rs": ["crates", "table"]}}, "merged_at": "2026-10-11T18:50:21Z", "pr": 19212, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/nushell/nushell/pull/19212"}, "query": {"anchor_diff": "@@ -1,4 +1,7 @@\n-use std::cmp::{max, min};\n+use std::{\n+ cmp::{max, min},\n+ collections::HashSet,\n+};\n \n use nu_color_config::{Alignment, StyleComputer, TextStyle};\n use nu_engine::column::get_columns;\n@@ -75,7 +78,7 @@ impl ExpandedTable {\n cfg.opts.mode,\n );\n \n- refit_nested_tables(&mut output, vals, cfg.clone())?;\n+ refit_nested_tables(&mut output, vals, &cfg)?;\n maybe_expand_table(output, cfg.opts.width)\n }\n }\n@@ -500,7 +503,7 @@ fn expand_value(value: &Value, width: usize, cfg: &Cfg<'_>) -> CellResult {\n match table {\n Some(mut out) => {\n table_apply_config(&mut out, cfg);\n- refit_nested_tables(&mut out, vals, inner_cfg)?;\n+ refit_nested_tables(&mut out, vals, &inner_cfg)?;\n let value = out.table.draw(width);\n match value {\n Some(value) => Ok(Some(CellOutput::clean(value, out.count_rows, true))),\n@@ -608,7 +611,7 @@ fn expand_entry(item: &Value, cfg: Cfg<'_>) -> CellOutput {\n };\n \n table_apply_config(&mut out, &cfg);\n- if refit_nested_tables(&mut out, vals, inner_cfg).is_err() {\n+ if refit_nested_tables(&mut out, vals, &inner_cfg).is_err() {\n let value = nu_value_to_string(item, cfg.opts.config, &cfg.opts.style_computer);\n let value = nutext_wrap(value, &cfg);\n return CellOutput::styled(value);\n@@ -669,19 +672,52 @@ fn list_to_string(\n buf\n }\n \n+/// Re-expands list and record cells that are wider than the column `draw` will give them.\n+///\n+/// Shrinking cells changes the widths `draw` plans from, so the next plan can\n+/// narrow a column again or bring back a column the last plan dropped. Re-plan\n+/// until no cell has to shrink. A cell is only replaced by a strictly narrower\n+/// one, so every repeated pass shrinks the table and the loop ends.\n fn refit_nested_tables(\n out: &mut TableOutput,\n input: &[Value],\n- cfg: Cfg<'_>,\n+ cfg: &Cfg<'_>,\n ) -> Result<(), ShellError> {\n if out.table.total_width() <= cfg.opts.width {\n return Ok(());\n }\n \n+ let with_index = out.with_index;\n+ let headers = get_columns(input);\n+ let headers: Vec<_> = headers\n+ .into_iter()\n+ .filter(|header| !with_index || header != INDEX_COLUMN_NAME)\n+ .collect();\n+\n+ // `(row, column, content width)` of re-expansions that did not shrink the\n+ // cell. The same width gives the same text, so later passes skip them.\n+ let mut no_progress = HashSet::new();\n+ while refit_nested_tables_once(out, input, &headers, cfg, &mut no_progress)? {}\n+\n+ Ok(())\n+}\n+\n+/// One planning pass of [`refit_nested_tables`]; returns whether a cell shrank.\n+fn refit_nested_tables_once(\n+ out: &mut TableOutput,\n+ input: &[Value],\n+ headers: &[String],\n+ cfg: &Cfg<'_>,\n+ no_progress: &mut HashSet<(usize, usize, usize)>,\n+) -> Result {\n+ if out.table.total_width() <= cfg.opts.width {\n+ return Ok(false);\n+ }\n+\n out.table.prefer_nested_table_columns();\n \n let Some((needed, trail)) = out.table.plan_column_widths(cfg.opts.width) else {\n- return Ok(());\n+ return Ok(false);\n };\n \n let pad = cfg.opts.config.table.padding.left + cfg.opts.config.table.padding.right;\n@@ -691,16 +727,11 @@ fn refit_nested_tables(\n needed.len()\n };\n if real_columns == 0 {\n- return Ok(());\n+ return Ok(false);\n }\n \n let with_index = out.with_index;\n let with_header = out.with_header;\n- let headers = get_columns(input);\n- let headers: Vec<_> = headers\n- .into_iter()\n- .filter(|header| !with_index || header != INDEX_COLUMN_NAME)\n- .collect();\n \n let mut replaced = false;\n for (col, col_width) in needed\n@@ -730,7 +761,10 @@ fn refit_nested_tables(\n break;\n }\n \n- if out.table.cell_content_width(table_row, col) <= content_width {\n+ let current_width = out.table.cell_content_width(table_row, col);\n+ if current_width <= content_width\n+ || no_progress.contains(&(table_row, col, content_width))\n+ {\n continue;\n }\n \n@@ -749,10 +783,20 @@ fn refit_nested_tables(\n inner_cfg.clip_columns = true;\n inner_cfg.raise_row_errors = false;\n let cell = expand_entry(value, inner_cfg);\n- let expanded = cell.is_expanded;\n- out.table.insert((table_row, col), cell.text);\n- if expanded {\n- out.table.mark_nested_cell((table_row, col));\n+ let text = NuTable::create(cell.text);\n+ if text.width() >= current_width {\n+ // No progress; `draw` cuts what still does not fit.\n+ no_progress.insert((table_row, col, content_width));\n+ continue;\n+ }\n+\n+ let pos = (table_row, col);\n+ out.table.insert_value(pos, text);\n+ // A nested table and its collapsed `[table N rows]` text are styled differently.\n+ out.table.reset_style(pos);\n+ out.table.insert_style(pos, cell.style);\n+ if cell.is_expanded {\n+ out.table.mark_nested_cell(pos);\n }\n replaced = true;\n }\n@@ -762,7 +806,7 @@ fn refit_nested_tables(\n out.table.recalculate_dimensions();\n }\n \n- Ok(())\n+ Ok(replaced)\n }\n \n fn maybe_expand_table(mut out: TableOutput, term_width: usize) -> StringResult {", "anchor_file": "crates/nu-table/src/types/expanded.rs", "intent": "fix(table): stop `table --expand` hanging when a nested table is wider than its column\n\n## Description\n\n`open Cargo.toml | [ $in ] | table -e -w 183` on main grows memory until the OOM killer ends nu. A debug build panics instead.\n\n### Before, debug build of main:\n\n```nushell\n> open Cargo.toml | [ $in ] | table -e -w 183 | ignore\nError: × Main thread panicked.\n ├─▶ at .../papergrid-0.18.0/src/grid/peekable.rs:985:20\n ╰─▶ attempt to subtract with overflow\n```\n\nBefore, release build of main (0.116.2 at 251b39276): no output, RSS climbs about 390 MB a second (406 MB after 1 s, 2.35 GB after 6 s) until killed. After, release build of this branch: 0.02 s, 24 MB peak RSS.\n\n### After:\n\n```nushell\n> open Cargo.toml | [ $in ] | table -e -w 183\n╭───┬────────────┬─────────────┬────────────┬────────────┬──────────────┬────────────┬───────────────┬────────────┬────────────┬────────────┬───────────┬────────────┬────────────────╮\n│ # │ package │ test │ workspace │ lints │ dependencies │ target │ build-depende │ dev-depend │ features │ profile │ bin │ patch │ bench │\n│ │ │ │ │ │ │ │ ncies │ encies │ │ │ │ │ │\n├───┼────────────┼─────────────┼────────────┼────────────┼──────────────┼────────────┼───────────────┼────────────┼────────────┼────────────┼───────────┼────────────┼────────────────┤\n│ 0 │ {record 15 │ ╭───┬─────╮ │ {record 4 │ {record 1 │ {record 33 │ {record 2 │ {record 1 │ {record 12 │ {record 14 │ {record 3 │ [table 1 │ {record 1 │ ╭───┬────────╮ │\n│ │ fields} │ │ # │ ... │ │ fields} │ field} │ fields} │ fields} │ field} │ fields} │ fields} │ fi\n...[truncated]"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "246cd631a3545aca3068f058d2b0d7b4eece3c60", "candidate_corpus": {"base_commit": "246cd631a3545aca3068f058d2b0d7b4eece3c60", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nu-command/src/filesystem/open.rs", "crates/nu-command/src/formats/mod.rs", "crates/nu-command/src/network/http/client.rs", "crates/nu-command/tests/commands/network/http/get.rs"], "given_files": ["crates/nu-command/src/filesystem/save.rs"]}, "id": "0d6208d21ac13d8f7e19654c", "metadata": {"changed_files": ["crates/nu-command/src/filesystem/open.rs", "crates/nu-command/src/filesystem/save.rs", "crates/nu-command/src/formats/alias_converter.rs", "crates/nu-command/src/formats/mod.rs", "crates/nu-command/src/network/http/client.rs", "crates/nu-command/tests/commands/network/http/get.rs", "crates/nu-command/tests/commands/open.rs", "crates/nu-command/tests/commands/save.rs"], "created_at": "2026-10-10T19:29:03Z", "fix_commit": "b23af9f4904204854af9f425e2f3417b4c006ed4", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 18, "deletions": 0, "is_test": false, "path": "crates/nu-command/src/filesystem/open.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 2, "deletions": 0, "is_test": false, "path": "crates/nu-command/src/formats/mod.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 14, "deletions": 6, "is_test": false, "path": "crates/nu-command/src/network/http/client.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 25, "deletions": 0, "is_test": true, "path": "crates/nu-command/tests/commands/network/http/get.rs", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"crates/nu-command/src/filesystem/open.rs": ["open", "command", "crates", "filesystem"], "crates/nu-command/src/formats/mod.rs": ["command", "crates", "formats"], "crates/nu-command/src/network/http/client.rs": ["command", "crates"], "crates/nu-command/tests/commands/network/http/get.rs": ["command", "commands", "crates"]}}, "merged_at": "2026-10-13T17:46:40Z", "pr": 19205, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/nushell/nushell/pull/19205"}, "query": {"anchor_diff": "@@ -151,7 +151,9 @@ impl Command for Save {\n let ext = extract_extension(&input, &path.item, raw);\n let converted = match ext {\n None => input,\n- Some(ext) => convert_to_extension(engine_state, &ext, stack, input, span)?,\n+ Some(ext) => {\n+ convert_to_extension(engine_state, &ext, stack, input, span, path.span)?\n+ }\n };\n \n // Save custom value however they implement saving\n@@ -309,17 +311,29 @@ fn extract_extension<'e>(input: &PipelineData, path: &'e Path, raw: bool) -> Opt\n \n /// Convert given data into content of file of specified extension if\n /// corresponding `to` command exists. Otherwise attempt to convert\n-/// data to bytes as is\n+/// data to bytes as is. `path_span` is the file argument, which an error about the converter\n+/// points at.\n fn convert_to_extension(\n engine_state: &EngineState,\n extension: &str,\n stack: &mut Stack,\n input: PipelineData,\n span: Span,\n+ path_span: Span,\n ) -> Result {\n if let Some(decl_id) = engine_state.find_decl(format!(\"to {extension}\").as_bytes(), &[]) {\n let decl = engine_state.get_decl(decl_id);\n- if let Some(block_id) = decl.block_id() {\n+ if let Some(alias) = decl.as_alias() {\n+ let file = String::from_utf8_lossy(engine_state.get_span_contents(path_span));\n+ Err(crate::formats::alias_converter_error(\n+ engine_state,\n+ alias,\n+ \"save\",\n+ \"save file\",\n+ &format!(\"... | {{}} | save {file}\"),\n+ path_span,\n+ ))\n+ } else if let Some(block_id) = decl.block_id() {\n let block = engine_state.get_block(block_id);\n let eval_block = get_eval_block(engine_state);\n eval_block(engine_state, stack, block, input).map(|p| p.body)", "anchor_file": "crates/nu-command/src/filesystem/save.rs", "intent": "`open`/`save`: give a clear error suggesting `def` when the `from`/`to` converter is an alias\n\n## Description\n\n`open` and `save` pick a converter by name at runtime: `open file.jsonc` looks up `from jsonc`, and `save file.jsonc` looks up `to jsonc`. When that name is an alias, for example `alias \"from jsonc\" = from json`, both commands call the alias itself. Aliases only exist while parsing, so this ends in an internal error that asks the user to file an issue:\n\n```\nError: nu::shell::nushell_failed_spanned\n × Nushell failed: Can't run alias directly. Unwrap it first.\n help: This shouldn't happen. Please file an issue\n```\n\nAs discussed in this PR, aliases aren't supported as converters. Both commands now check whether the converter they found is an alias, and if it is they return a normal error that suggests a `def` instead. The suggestion reuses the text the alias wraps, so the alias's flags are kept:\n\n```\nError: nu::shell::error\n\n x Can't open file with alias `from jsonc`\n ,-[source:1:38]\n 1 | alias \"from jsonc\" = from json; open deno.jsonc\n : ^^^^^|^^^^\n : `-- `from jsonc` is an alias, not a command\n `----\n help: `open` can only use a command as a converter. Define one with `def`\n instead: `def 'from jsonc' [] { from json }`\n```\n\n`save` gives the same error. It's raised before anything is written, so no file is created.\n\nTests:\n- `commands::open::open_with_a_from_alias_suggests_def`: a plain `from` alias, and one with `--noheaders` to check that the suggested `def` keeps the flag.\n- `commands::save::save_with_a_to_alias_suggests_def`: `alias \"to jsonc\" = to json --raw` suggests `def 'to jsonc' [] { to json --raw }` and doesn't create the file.\n\n`cargo fmt --all`, `cargo n\n...[truncated]"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "246cd631a3545aca3068f058d2b0d7b4eece3c60", "candidate_corpus": {"base_commit": "246cd631a3545aca3068f058d2b0d7b4eece3c60", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nu-command/src/formats/mod.rs", "crates/nu-command/src/filesystem/open.rs", "crates/nu-command/src/filesystem/save.rs", "crates/nu-command/tests/commands/network/http/get.rs"], "given_files": ["crates/nu-command/src/network/http/client.rs"]}, "id": "942fb83803a101d99126593c", "metadata": {"changed_files": ["crates/nu-command/src/filesystem/open.rs", "crates/nu-command/src/filesystem/save.rs", "crates/nu-command/src/formats/alias_converter.rs", "crates/nu-command/src/formats/mod.rs", "crates/nu-command/src/network/http/client.rs", "crates/nu-command/tests/commands/network/http/get.rs", "crates/nu-command/tests/commands/open.rs", "crates/nu-command/tests/commands/save.rs"], "created_at": "2026-10-10T19:29:03Z", "fix_commit": "b23af9f4904204854af9f425e2f3417b4c006ed4", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 2, "deletions": 0, "is_test": false, "path": "crates/nu-command/src/formats/mod.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 18, "deletions": 0, "is_test": false, "path": "crates/nu-command/src/filesystem/open.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 17, "deletions": 3, "is_test": false, "path": "crates/nu-command/src/filesystem/save.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 25, "deletions": 0, "is_test": true, "path": "crates/nu-command/tests/commands/network/http/get.rs", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"crates/nu-command/src/filesystem/open.rs": ["open", "command", "crates"], "crates/nu-command/src/filesystem/save.rs": ["save", "command", "crates"], "crates/nu-command/src/formats/mod.rs": ["command", "crates", "formats"], "crates/nu-command/tests/commands/network/http/get.rs": ["command", "commands", "crates", "http", "network"]}}, "merged_at": "2026-10-13T17:46:40Z", "pr": 19205, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/nushell/nushell/pull/19205"}, "query": {"anchor_diff": "@@ -1024,12 +1024,20 @@ fn transform_response_using_content_type(\n Ok(output)\n } else if let Some(ext) = ext {\n match engine_state.find_decl(format!(\"from {ext}\").as_bytes(), &[]) {\n- Some(converter_id) => engine_state.get_decl(converter_id).run(\n- engine_state,\n- stack,\n- &Call::new(span),\n- output,\n- ),\n+ Some(converter_id) => {\n+ let decl = engine_state.get_decl(converter_id);\n+ if let Some(alias) = decl.as_alias() {\n+ return Err(crate::formats::alias_converter_error(\n+ engine_state,\n+ alias,\n+ \"http\",\n+ \"convert the response\",\n+ &format!(\"http ... --raw {requested_url} | {{}}\"),\n+ span,\n+ ));\n+ }\n+ decl.run(engine_state, stack, &Call::new(span), output)\n+ }\n None => Ok(output),\n }\n } else {", "anchor_file": "crates/nu-command/src/network/http/client.rs", "intent": "`open`/`save`: give a clear error suggesting `def` when the `from`/`to` converter is an alias\n\n## Description\n\n`open` and `save` pick a converter by name at runtime: `open file.jsonc` looks up `from jsonc`, and `save file.jsonc` looks up `to jsonc`. When that name is an alias, for example `alias \"from jsonc\" = from json`, both commands call the alias itself. Aliases only exist while parsing, so this ends in an internal error that asks the user to file an issue:\n\n```\nError: nu::shell::nushell_failed_spanned\n × Nushell failed: Can't run alias directly. Unwrap it first.\n help: This shouldn't happen. Please file an issue\n```\n\nAs discussed in this PR, aliases aren't supported as converters. Both commands now check whether the converter they found is an alias, and if it is they return a normal error that suggests a `def` instead. The suggestion reuses the text the alias wraps, so the alias's flags are kept:\n\n```\nError: nu::shell::error\n\n x Can't open file with alias `from jsonc`\n ,-[source:1:38]\n 1 | alias \"from jsonc\" = from json; open deno.jsonc\n : ^^^^^|^^^^\n : `-- `from jsonc` is an alias, not a command\n `----\n help: `open` can only use a command as a converter. Define one with `def`\n instead: `def 'from jsonc' [] { from json }`\n```\n\n`save` gives the same error. It's raised before anything is written, so no file is created.\n\nTests:\n- `commands::open::open_with_a_from_alias_suggests_def`: a plain `from` alias, and one with `--noheaders` to check that the suggested `def` keeps the flag.\n- `commands::save::save_with_a_to_alias_suggests_def`: `alias \"to jsonc\" = to json --raw` suggests `def 'to jsonc' [] { to json --raw }` and doesn't create the file.\n\n`cargo fmt --all`, `cargo n\n...[truncated]"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "246cd631a3545aca3068f058d2b0d7b4eece3c60", "candidate_corpus": {"base_commit": "246cd631a3545aca3068f058d2b0d7b4eece3c60", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nu-command/src/conversions/into/duration.rs", "crates/nu-command/src/strings/detect_type.rs", "crates/nu-command/tests/commands/detect_type.rs"], "given_files": ["crates/nu-command/src/conversions/into/mod.rs"]}, "id": "11f3e7cffafe0c15e561dc84", "metadata": {"changed_files": ["crates/nu-command/src/conversions/into/duration.rs", "crates/nu-command/src/conversions/into/mod.rs", "crates/nu-command/src/strings/detect_type.rs", "crates/nu-command/tests/commands/detect_type.rs"], "created_at": "2026-10-10T13:50:01Z", "fix_commit": "af37214641d62d104523ce36eeaac6a6323a005a", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "crates/nu-command/src/conversions/into/duration.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 8, "deletions": 0, "is_test": false, "path": "crates/nu-command/src/strings/detect_type.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 3, "deletions": 0, "is_test": true, "path": "crates/nu-command/tests/commands/detect_type.rs", "signals": ["path_token_overlap", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"crates/nu-command/src/conversions/into/duration.rs": ["duration", "command", "conversions", "crates", "into"], "crates/nu-command/src/strings/detect_type.rs": ["command", "crates", "detect", "type"], "crates/nu-command/tests/commands/detect_type.rs": ["command", "crates", "detect", "type"]}}, "merged_at": "2026-10-10T23:23:27Z", "pr": 19204, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/nushell/nushell/pull/19204"}, "query": {"anchor_diff": "@@ -31,3 +31,5 @@ pub use semver::IntoSemver;\n pub use semver_range::IntoSemverRange;\n pub use string::IntoString;\n pub use value::IntoValue;\n+\n+pub(crate) use duration::compound_to_duration;", "anchor_file": "crates/nu-command/src/conversions/into/mod.rs", "intent": "detect duration type\n\n## Description\n\n`detect type` tries to use the composite duration parsing logic from `into duration`. Successful parse = we detected a duration.\n\n## User-facing changes (Release notes)\n\n`detect type` understands how to parse composite durations\n\n```nushell\n\"1hr 3min\" | detect type | describe # duration\n```\n\nCloses #19203\n\ndetect duration type"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "246cd631a3545aca3068f058d2b0d7b4eece3c60", "candidate_corpus": {"base_commit": "246cd631a3545aca3068f058d2b0d7b4eece3c60", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nu-command/src/conversions/into/mod.rs", "crates/nu-command/src/strings/detect_type.rs", "crates/nu-command/tests/commands/detect_type.rs"], "given_files": ["crates/nu-command/src/conversions/into/duration.rs"]}, "id": "64dfed383fd558fdf6c009fd", "metadata": {"changed_files": ["crates/nu-command/src/conversions/into/duration.rs", "crates/nu-command/src/conversions/into/mod.rs", "crates/nu-command/src/strings/detect_type.rs", "crates/nu-command/tests/commands/detect_type.rs"], "created_at": "2026-10-10T13:50:01Z", "fix_commit": "af37214641d62d104523ce36eeaac6a6323a005a", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 2, "deletions": 0, "is_test": false, "path": "crates/nu-command/src/conversions/into/mod.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 8, "deletions": 0, "is_test": false, "path": "crates/nu-command/src/strings/detect_type.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 3, "deletions": 0, "is_test": true, "path": "crates/nu-command/tests/commands/detect_type.rs", "signals": ["path_token_overlap", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"crates/nu-command/src/conversions/into/mod.rs": ["command", "conversions", "crates", "into"], "crates/nu-command/src/strings/detect_type.rs": ["command", "crates", "detect", "type"], "crates/nu-command/tests/commands/detect_type.rs": ["command", "crates", "detect", "type"]}}, "merged_at": "2026-10-10T23:23:27Z", "pr": 19204, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/nushell/nushell/pull/19204"}, "query": {"anchor_diff": "@@ -229,7 +229,7 @@ fn parse_string_duration(s: &str, span: Span) -> Result {\n }\n }\n \n-fn compound_to_duration(s: &str, span: Span) -> Result {\n+pub(crate) fn compound_to_duration(s: &str, span: Span) -> Result {\n let mut parts = split_whitespace_indices(s, span)\n .map(|(substring, substring_span)| string_to_duration(substring, substring_span))\n .peekable();", "anchor_file": "crates/nu-command/src/conversions/into/duration.rs", "intent": "detect duration type\n\n## Description\n\n`detect type` tries to use the composite duration parsing logic from `into duration`. Successful parse = we detected a duration.\n\n## User-facing changes (Release notes)\n\n`detect type` understands how to parse composite durations\n\n```nushell\n\"1hr 3min\" | detect type | describe # duration\n```\n\nCloses #19203\n\ndetect duration type"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "9149ea5ede28cd618886ebd0e767ba90694515ca", "candidate_corpus": {"base_commit": "9149ea5ede28cd618886ebd0e767ba90694515ca", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nu-command/tests/commands/str_/into_string.rs"], "given_files": ["crates/nu-command/src/conversions/into/string.rs"]}, "id": "5a9b70318cdee38ddd00afd3", "metadata": {"changed_files": ["crates/nu-command/src/conversions/into/string.rs", "crates/nu-command/tests/commands/str_/into_string.rs"], "created_at": "2026-10-08T15:49:25Z", "fix_commit": "c3b7a5aebea0119d88bba4608bc6a3f81bb54a45", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 62, "deletions": 0, "is_test": true, "path": "crates/nu-command/tests/commands/str_/into_string.rs", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"crates/nu-command/tests/commands/str_/into_string.rs": ["command", "crates", "into", "string"]}}, "merged_at": "2026-10-09T16:49:32Z", "pr": 19191, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/nushell/nushell/pull/19191"}, "query": {"anchor_diff": "@@ -175,6 +175,18 @@ fn string_helper(\n span: head,\n });\n }\n+ if let Some(decimal_val) = decimals_value\n+ && decimal_val > u16::MAX as i64\n+ {\n+ return Err(ShellError::IncorrectValue {\n+ msg: format!(\n+ \"Cannot accept more than {} decimal digits for the decimals argument\",\n+ u16::MAX\n+ ),\n+ val_span: head,\n+ call_span: head,\n+ });\n+ }\n let cell_paths = call.rest(engine_state, stack, 0)?;\n let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);\n \n@@ -226,8 +238,8 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {\n let basic = digits.map_or_else(\n || val.to_string(),\n |precision| {\n- let rounded = (val * 10_f64.powi(precision as i32)).round()\n- / 10_f64.powi(precision as i32);\n+ let scale = 10_f64.powi(precision as i32);\n+ let rounded = (val * scale).round() / scale;\n format!(\"{:.*}\", precision as usize, rounded)\n },\n );", "anchor_file": "crates/nu-command/src/conversions/into/string.rs", "intent": "fix: reject out-of-range decimals in into string\n\n## Description\n\n`into string -d ` panics when the precision is large enough that `10_f64.powi(precision as i32)` underflows to zero. The division then produces NaN, and `format!(\"{:.*}\", precision, NaN)` panics with \"Formatting argument out of range\".\n\nRepro: `1.5 | into string -d 2147483648`\n\nThe `i64` precision is cast to `i32` for `powi`, so values above `i32::MAX` wrap to negative, producing `10^(-2147483648) = 0`, then `NaN`. The `is_finite()` guard earlier in the function only checks the input value, not the rounded result.\n\nReturn the original value's string form when the rounding produces NaN.\n\n## User-facing changes\n\n`into string` with a very large `-d` value no longer panics; it returns the unrounded value.\n\n## Additional notes\n\nVerified with a standalone Rust repro that `(1.5 * 10^(-2147483648)).round() / 10^(-2147483648)` is NaN and `format!(\"{:.*}`, 2147483648, NaN)` panics.\n\nfix: return the original value when into string -d produces NaN\n\nfix: reject decimals above u16::MAX in into string"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "3b08da67d19de7982a6612bca1eea4009fee2f9b", "candidate_corpus": {"base_commit": "3b08da67d19de7982a6612bca1eea4009fee2f9b", "type": "repo_at_base_commit"}, "gold": {"files": ["Cargo.toml"], "given_files": ["crates/nu-cli/src/reedline_config.rs"]}, "id": "9593392e20d1f9e22b3db84a", "metadata": {"changed_files": ["Cargo.lock", "Cargo.toml", "crates/nu-cli/src/reedline_config.rs"], "created_at": "2026-10-06T16:45:38Z", "fix_commit": "88bf737d8df2f3aab12cdf4c2b3c676dd7abf58f", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "Cargo.toml", "signals": ["shared_changed_symbol", "shared_config_or_schema"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": [], "nonfatal_hits": {}}, "merged_at": "2026-10-06T18:51:23Z", "pr": 19175, "ripple_relation": ["shared_changed_symbol", "shared_config_or_schema"], "source_pr": "https://github.com/nushell/nushell/pull/19175"}, "query": {"anchor_diff": "@@ -15,9 +15,9 @@ use reedline::{\n EditCommandDiscriminants, FindStop, Granularity, IdeMenu, InputMode, Keybindings, ListMenu,\n Menu, MenuBuilder, MotionTarget, OutputMode, PromptEditMode, PromptEditModeDiscriminants,\n PromptHelixMode, PromptViMode, Reedline, ReedlineEvent, ReedlineEventDiscriminants,\n- ReedlineMenu, TextObject, TextObjectScope, TextObjectType, TraversalDirection, WordEdge,\n- WordKind, default_emacs_keybindings, default_vi_insert_keybindings,\n- default_vi_normal_keybindings, default_vi_visual_keybindings,\n+ ReedlineMenu, TextObject, TextObjectBracket, TextObjectQuote, TextObjectScope, TextObjectType,\n+ TraversalDirection, WordEdge, WordKind, default_emacs_keybindings,\n+ default_vi_insert_keybindings, default_vi_normal_keybindings, default_vi_visual_keybindings,\n };\n use reedline::{\n default_helix_insert_keybindings, default_helix_normal_keybindings,\n@@ -1120,6 +1120,9 @@ fn edit_from_record(\n span: Span,\n ) -> Result {\n use EditCommandDiscriminants as ECD;\n+ if let Some(edit) = legacy_pair_edit(name, record, span)? {\n+ return Ok(edit);\n+ }\n // When updating this implementation, also update `display_edit_command` function\n let edit = match ECD::from_str(name) {\n Ok(ECD::MoveToStart) => EditCommand::MoveToStart {\n@@ -1390,34 +1393,6 @@ fn edit_from_record(\n Ok(ECD::CopySelectionSystem) => EditCommand::CopySelectionSystem,\n #[cfg(feature = \"system-clipboard\")]\n Ok(ECD::PasteSystem) => EditCommand::PasteSystem,\n- Ok(ECD::CutInsidePair) => {\n- let value = extract_value(\"left\", record, span)?;\n- let left = extract_char(value)?;\n- let value = extract_value(\"right\", record, span)?;\n- let right = extract_char(value)?;\n- EditCommand::CutInsidePair { left, right }\n- }\n- Ok(ECD::CopyInsidePair) => {\n- let value = extract_value(\"left\", record, span)?;\n- let left = extract_char(value)?;\n- let value = extract_value(\"right\", record, span)?;\n- let right = extract_char(value)?;\n- EditCommand::CopyInsidePair { left, right }\n- }\n- Ok(ECD::CutAroundPair) => {\n- let value = extract_value(\"left\", record, span)?;\n- let left = extract_char(value)?;\n- let value = extract_value(\"right\", record, span)?;\n- let right = extract_char(value)?;\n- EditCommand::CutAroundPair { left, right }\n- }\n- Ok(ECD::CopyAroundPair) => {\n- let value = extract_value(\"left\", record, span)?;\n- let left = extract_char(value)?;\n- let value = extract_value(\"right\", record, span)?;\n- let right = extract_char(value)?;\n- EditCommand::CopyAroundPair { left, right }\n- }\n Ok(ECD::CopyTextObject) => EditCommand::CopyTextObject {\n text_object: parse_text_object(record, config, span)?,\n },\n@@ -1453,6 +1428,19 @@ fn edit_from_record(\n .and_then(|count| usize::try_from(count).ok())\n .unwrap_or(1),\n },\n+ Ok(ECD::SelectTextObject) => {\n+ EditCommand::SelectTextObject(parse_text_object(record, config, span)?)\n+ }\n+ Ok(ECD::AddTextObject) => EditCommand::AddTextObject {\n+ text_object: parse_pair_type(\"object_type\", record, config, span)?,\n+ },\n+ Ok(ECD::RemoveTextObject) => EditCommand::RemoveTextObject {\n+ text_object: parse_pair_type(\"object_type\", record, config, span)?,\n+ },\n+ Ok(ECD::ReplaceTextObject) => EditCommand::ReplaceTextObject {\n+ old: parse_pair_type(\"old\", record, config, span)?,\n+ new: parse_pair_type(\"new\", record, config, span)?,\n+ },\n // `EditCommand::ReplaceChars` - Internal hack not sanely implementable as a\n // standalone binding\n Ok(ECD::ReplaceChars) | Err(_) => {\n@@ -1574,12 +1562,12 @@ pub(crate) fn display_edit_command(edit: EditCommandDiscriminants) -> Option<&'s\n ECD::CopySelectionSystem => \"CopySelectionSystem\",\n #[cfg(feature = \"system-clipboard\")]\n ECD::PasteSystem => \"PasteSystem\",\n- ECD::CutInsidePair => \"CutInsidePair left: , right \",\n- ECD::CopyInsidePair => \"CopyInsidePair left: , right \",\n- ECD::CutAroundPair => \"CutAroundPair left: , right \",\n- ECD::CopyAroundPair => \"CopyAroundPair left: , right \",\n- ECD::CutTextObject => \"CutTextObject scope: , object_type: \",\n- ECD::CopyTextObject => \"CopyTextObject scope: , object_type: \",\n+ ECD::CutTextObject => {\n+ \"CutTextObject scope: , object_type: , check_next?: \"\n+ }\n+ ECD::CopyTextObject => {\n+ \"CopyTextObject scope: , object_type: , check_next?: \"\n+ }\n ECD::Move => {\n \"Move motion: , direction: , word_kind?: , edge?: , char?: , stop?: \"\n }\n@@ -1603,6 +1591,14 @@ pub(crate) fn display_edit_command(edit: EditCommandDiscriminants) -> Option<&'s\n }\n ECD::CollapseSelection => \"CollapseSelection direction: \",\n ECD::PasteAtSelectionEdge => \"PasteAtSelectionEdge direction: , count?: \",\n+ ECD::SelectTextObject => {\n+ \"SelectTextObject scope: , object_type: , check_next?: \"\n+ }\n+ ECD::AddTextObject => \"AddTextObject object_type: \",\n+ ECD::RemoveTextObject => \"RemoveTextObject object_type: \",\n+ ECD::ReplaceTextObject => {\n+ \"ReplaceTextObject old: , new: \"\n+ }\n ECD::ReplaceChars => return None,\n })\n }\n@@ -1645,22 +1641,116 @@ fn parse_text_object(\n },\n )?;\n \n- let object_type = extract_enum_field(\n- \"object_type\",\n- record,\n- config,\n- span,\n- \"'word', 'bigword', 'brackets', or 'quote'\",\n- |name| match name {\n- \"word\" => Some(TextObjectType::Word),\n- \"bigword\" => Some(TextObjectType::BigWord),\n- \"brackets\" | \"bracket\" => Some(TextObjectType::Brackets),\n- \"quote\" | \"quotes\" => Some(TextObjectType::Quote),\n- _ => None,\n- },\n- )?;\n+ let object_type = parse_object_type(\"object_type\", record, config, span)?;\n+\n+ // With the cursor outside any match, act on the next one unless told\n+ // otherwise, as these commands did before reedline made it optional.\n+ let check_next = extract_value(\"check_next\", record, span)\n+ .and_then(|value| value.as_bool())\n+ .unwrap_or(true);\n \n- Ok(TextObject { scope, object_type })\n+ Ok(TextObject {\n+ scope,\n+ object_type,\n+ check_next,\n+ })\n+}\n+\n+const OBJECT_TYPES: &str = \"'word', 'bigword', 'brackets', 'quotes', 'parentheses', \\\n+ 'square_brackets', 'curly_brackets', 'angle_brackets', 'single_quotes', 'double_quotes', \\\n+ 'backticks', or a record { left: , right: }\";\n+\n+/// A text object type by name. `brackets` and `quotes` match any of their kind,\n+/// the others one pair.\n+fn object_type_by_name(name: &str) -> Option {\n+ use TextObjectBracket as B;\n+ use TextObjectQuote as Q;\n+ Some(match name {\n+ \"word\" => TextObjectType::Word,\n+ \"bigword\" => TextObjectType::BigWord,\n+ \"brackets\" | \"bracket\" => TextObjectType::Brackets(B::All),\n+ \"quotes\" | \"quote\" => TextObjectType::Quotes(Q::All),\n+ \"parentheses\" | \"parenthesis\" => TextObjectType::Brackets(B::Parenthesis),\n+ \"square_brackets\" | \"square_bracket\" => TextObjectType::Brackets(B::SquareBracket),\n+ \"curly_brackets\" | \"curly_bracket\" => TextObjectType::Brack\n...[truncated]", "anchor_file": "crates/nu-cli/src/reedline_config.rs", "intent": "chore: bump reedline to e9fcfdb\n\n## Description\n\nBumps reedline to `e9fcfdb`, eight PRs past the 0.52.1 release:\n\n- nushell/reedline#1240 `fix(helix): give h and l the arrow keys' fallbacks in normal mode`\n- nushell/reedline#1239 `fix(engine): keep auto-pairs out of menu queries and hint before trailing closers`\n- nushell/reedline#1234 `docs(engine): spell out what a templated buffer editor keeps, test envs`\n- nushell/reedline#1233 `fix(painter): hide the cursor before the anchor query`\n- nushell/reedline#1224 `docs: fill Completion and VI sections in UX_TESTING.md`\n- nushell/reedline#1188 `feat(editor): Add helix match selection`\n- nushell/reedline#1041 `feat: accept templated command for OpenEditor`\n- nushell/reedline#1236 `fix(painter): saturate the large buffer line math for 0/1-row terminals`\n\n#1188 replaced the `CutInsidePair`, `CopyInsidePair`, `CutAroundPair` and `CopyAroundPair` edit commands with the text object ones and added `SelectTextObject`, `AddTextObject`, `RemoveTextObject` and `ReplaceTextObject`.\nThis PR brings the keybinding config in line with that, so every text object command reedline has can be bound.\nThe four removed names still parse, onto the matching text object command, so existing configs keep working.\n\n## User-facing changes (Release notes)\n\n- In helix mode `h` and `l` now step through an open menu, and `l` accepts a history hint, as the arrow keys and vi's `h`/`l` do.\n- Helix mode gained the match commands under `m`: select inside or around a pair, add one around the selection, and delete or replace the nearest one.\n- The cursor no longer shows at the start of the next line while the prompt waits on the terminal's position report.\n- Text object edit commands take more values in the keybinding config:\n - `object_type` takes `word`, `bigw\n...[truncated]"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "c14a6f383633c4828532c69e08cd779d11094484", "candidate_corpus": {"base_commit": "c14a6f383633c4828532c69e08cd779d11094484", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nu-command/src/math/round.rs", "crates/nu-command/tests/commands/str_/into_string.rs"], "given_files": ["crates/nu-command/src/conversions/into/string.rs"]}, "id": "a23e6587114c9cd041cb64f8", "metadata": {"changed_files": ["crates/nu-command/src/conversions/into/string.rs", "crates/nu-command/src/math/round.rs", "crates/nu-command/tests/commands/str_/into_string.rs"], "created_at": "2026-10-05T17:40:14Z", "fix_commit": "15b810275b6759d4b6de85c5da0cfacee5fff407", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 2, "deletions": 2, "is_test": false, "path": "crates/nu-command/src/math/round.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 173, "deletions": 0, "is_test": true, "path": "crates/nu-command/tests/commands/str_/into_string.rs", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"crates/nu-command/src/math/round.rs": ["round", "command", "crates", "math"], "crates/nu-command/tests/commands/str_/into_string.rs": ["command", "crates", "into", "str", "string"]}}, "merged_at": "2026-10-06T14:52:41Z", "pr": 19166, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/nushell/nushell/pull/19166"}, "query": {"anchor_diff": "@@ -2,7 +2,7 @@ use nu_cmd_base::input_handler::{CmdArgument, operate};\n use nu_engine::command_prelude::*;\n use nu_protocol::Config;\n use nu_utils::get_system_locale;\n-use num_format::ToFormattedString;\n+use num_format::{Grouping, ToFormattedString};\n use std::sync::Arc;\n \n struct Arguments {\n@@ -219,12 +219,90 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {\n Value::string(res, span)\n }\n Value::Float { val, .. } => {\n- if let Some(decimal_value) = digits {\n- let decimal_value = decimal_value as usize;\n- Value::string(format!(\"{val:.decimal_value$}\"), span)\n- } else {\n- Value::string(val.to_string(), span)\n+ if !val.is_finite() {\n+ return Value::string(val.to_string(), span);\n+ }\n+\n+ let basic = digits.map_or_else(\n+ || val.to_string(),\n+ |precision| {\n+ let rounded = (val * 10_f64.powi(precision as i32)).round()\n+ / 10_f64.powi(precision as i32);\n+ format!(\"{:.*}\", precision as usize, rounded)\n+ },\n+ );\n+\n+ let first_digit = if val.is_sign_negative() { 1 } else { 0 };\n+ let decimal = basic.find('.').unwrap_or(basic.len());\n+ let decimal_len = decimal - first_digit;\n+ let locale = get_system_locale();\n+ if !group_digits\n+ || match locale.grouping() {\n+ Grouping::Posix => true,\n+ Grouping::Standard | Grouping::Indian => decimal < 4,\n+ }\n+ {\n+ let basic = format!(\n+ \"{}{}{}{}\",\n+ if val.is_sign_negative() {\n+ locale.minus_sign()\n+ } else {\n+ \"\"\n+ },\n+ &basic[first_digit..decimal],\n+ if decimal < basic.len() {\n+ locale.decimal()\n+ } else {\n+ \"\"\n+ },\n+ if decimal < basic.len() {\n+ &basic[decimal + 1..]\n+ } else {\n+ \"\"\n+ }\n+ );\n+ return Value::string(basic, span);\n+ }\n+\n+ let (size, start, step) = match locale.grouping() {\n+ Grouping::Posix => {\n+ unreachable!(\"Posix locale grouping should already have returned\")\n+ }\n+ Grouping::Standard => (\n+ basic.len() + (decimal - first_digit) / 3 * locale.separator().len(),\n+ if decimal_len.is_multiple_of(3) {\n+ first_digit + 3\n+ } else {\n+ first_digit + decimal_len % 3\n+ },\n+ 3,\n+ ),\n+ Grouping::Indian => (\n+ basic.len() + ((decimal_len - 3) / 2 + 1) * locale.separator().len(),\n+ if (decimal_len - 3).is_multiple_of(2) {\n+ first_digit + 2\n+ } else {\n+ first_digit + (decimal_len - 3) % 2\n+ },\n+ 2,\n+ ),\n+ };\n+ let mut result = String::with_capacity(size);\n+ if val.is_sign_negative() {\n+ result.push_str(locale.minus_sign());\n+ }\n+ result.push_str(&basic[first_digit..start]);\n+ for start in (start..(decimal - 3)).step_by(step) {\n+ result.push_str(locale.separator());\n+ result.push_str(&basic[start..(start + step)])\n+ }\n+ result.push_str(locale.separator());\n+ result.push_str(&basic[(decimal - 3)..decimal]);\n+ if decimal < basic.len() {\n+ result.push_str(locale.decimal());\n+ result.push_str(&basic[decimal + 1..]);\n }\n+ Value::string(result, span)\n }\n Value::Bool { val, .. } => Value::string(val.to_string(), span),\n Value::Date { val, .. } => Value::string(val.format(\"%c\").to_string(), span),\n@@ -293,6 +371,8 @@ fn format_int(int: i64, group_digits: bool, decimals: usize) -> String {\n \n let str = if group_digits {\n int.to_formatted_string(&locale)\n+ } else if int < 0 {\n+ format!(\"{}{}\", locale.minus_sign(), int.abs())\n } else {\n int.to_string()\n };", "anchor_file": "crates/nu-command/src/conversions/into/string.rs", "intent": "Correct float `into string` conversions\n\n## Description\n\nFix #16772 by implementing string-based decimal grouping for `into string` on floats and adding locale support.\n\nBecause floating point conversion into decimal strings is tricky, continue to use Rust's implementation, then modify it's output with grouping and locale strings.\n\nThe rounding behavior of into string was also inconsistent with `math round`. See these results:\n```\n[[base]; [0.5] [1.5]]\n | insert math {$in.base | math round}\n | insert str { $in.base | into string -d 0}\n\n # base math str\n───────────────────────\n 0 0.50 1 0\n 1 1.50 2 2\n```\nManually round the floats in the same manner in both places. Update to use the slightly more efficient `f64.powi()` method instead of `f64.powf()`.\n\n## User-facing changes (Release notes)\nAdded support to `into string` for locales and `--group-digits` with floating point input. Made the `into string` rounding match `math round`.\n\n## Additional notes\nfixes #16772\n\nCorrect float `into string` conversions\n\nCorrect negative numbers\n\nFormat into/string.rs\n\nMerge branch 'nushell:main' into main\n\nAddress clippy preferences"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "fd5721afce616909ed9ff2df9ca7467882fc15a5", "candidate_corpus": {"base_commit": "fd5721afce616909ed9ff2df9ca7467882fc15a5", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nuon/src/to.rs", "crates/nuon/Cargo.toml"], "given_files": ["crates/nuon/src/lib.rs"]}, "id": "5b4867a6c418abde92dfb44d", "metadata": {"changed_files": ["Cargo.lock", "crates/nuon/Cargo.toml", "crates/nuon/spec/bugs_to_fix.md", "crates/nuon/src/lib.rs", "crates/nuon/src/to.rs"], "created_at": "2026-10-05T16:43:22Z", "fix_commit": "549e72d518d98ae772bf2bcbd78366474da42b99", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 23, "deletions": 9, "is_test": false, "path": "crates/nuon/src/to.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 1, "deletions": 0, "is_test": false, "path": "crates/nuon/Cargo.toml", "signals": ["path_token_overlap", "shared_config_or_schema"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"crates/nuon/Cargo.toml": ["crates", "nuon"], "crates/nuon/src/to.rs": ["crates", "nuon"]}}, "merged_at": "2026-10-07T11:32:32Z", "pr": 19165, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"], "source_pr": "https://github.com/nushell/nushell/pull/19165"}, "query": {"anchor_diff": "@@ -703,4 +703,54 @@ version = \"1.0.0\"\n // roundtrip: aligned output parses back to the same value\n assert_eq!(val, from_nuon(&result, None).unwrap());\n }\n+\n+ #[test]\n+ fn table_column_alignment_with_non_ascii_cells() {\n+ let engine_state = EngineState::new();\n+ let val = Value::test_list(vec![\n+ Value::test_record(record!(\n+ \"a\" => Value::test_string(\"日本\"),\n+ \"b\" => Value::test_int(1)\n+ )),\n+ Value::test_record(record!(\n+ \"a\" => Value::test_string(\"abcde\"),\n+ \"b\" => Value::test_int(2)\n+ )),\n+ ]);\n+ let result = to_nuon(\n+ &engine_state,\n+ &val,\n+ ToNuonConfig::default().style(ToStyle::Spaces(2)),\n+ )\n+ .unwrap();\n+\n+ assert_eq!(result, \"[\\n [a, b];\\n [日本, 1],\\n [abcde, 2]\\n]\");\n+ // roundtrip: aligned output still parses back to the same value\n+ assert_eq!(val, from_nuon(&result, None).unwrap());\n+ }\n+\n+ #[test]\n+ fn table_column_alignment_with_multibyte_single_rune_cells() {\n+ // `…` is one rune but three bytes, the other direction of the same mismatch.\n+ let engine_state = EngineState::new();\n+ let val = Value::test_list(vec![\n+ Value::test_record(record!(\n+ \"a\" => Value::test_string(\"…\"),\n+ \"b\" => Value::test_int(1)\n+ )),\n+ Value::test_record(record!(\n+ \"a\" => Value::test_string(\"abcde\"),\n+ \"b\" => Value::test_int(2)\n+ )),\n+ ]);\n+ let result = to_nuon(\n+ &engine_state,\n+ &val,\n+ ToNuonConfig::default().style(ToStyle::Spaces(2)),\n+ )\n+ .unwrap();\n+\n+ assert_eq!(result, \"[\\n [a, b];\\n […, 1],\\n [abcde, 2]\\n]\");\n+ assert_eq!(val, from_nuon(&result, None).unwrap());\n+ }\n }", "anchor_file": "crates/nuon/src/lib.rs", "intent": "Measure nuon table column widths in runes, not bytes\n\n## Description\n\n`to nuon --pretty` measures table column widths in bytes while padding in runes, so a column containing a multi-byte cell is padded wider than the format asks for. This makes the column as wide as the widest cell's byte length instead of its rune count.\n\nThis is a canonicalization fix, not a terminal-alignment fix, and I want to be accurate about which is which.\n\n```\n[[a, b]; [\"日本\", 1], [\"abcde\", 2]] | to nuon --pretty\n\n main this branch\n [a, b]; [a, b];\n [日本, 1], [日本, 1],\n [abcde, 2] [abcde, 2]\n```\n\n`日本` is 2 runes and 6 bytes. Byte widths make the first column 6 wide where 5 is the widest cell's rune count, so every row in that column gets one space of padding nobody asked for. Rows still lined up with each other before this change, and they still do; what changes is the width of the column, not the alignment between rows.\n\n## The fix\n\nMeasure the widths in the same unit the padding uses:\n\n```rust\n// Column widths = max of header and cell widths per column.\n// Counted in chars, not bytes: the padding below is applied with `{: = col_names.iter().map(|h| h.chars().count()).collect();\n```\n\nThis is bug 6 in `crates/nuon/spec/bugs_to_fix.md`, whose entry I have ticked as that file asks. The spec asks for one measure on both sides, which is what this does.\n\n**Terminal display width, and why not.** Display width is the measure that would make CJK and ASCII line up visually, and it is available — `unicode-width` is already a workspace dependency and `nu-term-grid` uses it. I deliberately did not use it here. Display width is\n...[truncated]"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "fd5721afce616909ed9ff2df9ca7467882fc15a5", "candidate_corpus": {"base_commit": "fd5721afce616909ed9ff2df9ca7467882fc15a5", "type": "repo_at_base_commit"}, "gold": {"files": ["crates/nuon/Cargo.toml", "crates/nuon/src/lib.rs"], "given_files": ["crates/nuon/src/to.rs"]}, "id": "97fb7c4b6ad2c6f7e100ec02", "metadata": {"changed_files": ["Cargo.lock", "crates/nuon/Cargo.toml", "crates/nuon/spec/bugs_to_fix.md", "crates/nuon/src/lib.rs", "crates/nuon/src/to.rs"], "created_at": "2026-10-05T16:43:22Z", "fix_commit": "549e72d518d98ae772bf2bcbd78366474da42b99", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 1, "deletions": 0, "is_test": false, "path": "crates/nuon/Cargo.toml", "signals": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"]}, {"additions": 50, "deletions": 0, "is_test": false, "path": "crates/nuon/src/lib.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"crates/nuon/Cargo.toml": ["crates", "nuon"], "crates/nuon/src/lib.rs": ["crates", "nuon"]}}, "merged_at": "2026-10-07T11:32:32Z", "pr": 19165, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema", "same_component"], "source_pr": "https://github.com/nushell/nushell/pull/19165"}, "query": {"anchor_diff": "@@ -2,6 +2,7 @@ use core::fmt::Write;\n use nu_engine::get_columns;\n use nu_protocol::{Range, ShellError, Span, Value, engine::EngineState};\n use nu_utils::{ObviousFloat, as_raw_string, escape_quote_string, needs_quoting};\n+use unicode_width::UnicodeWidthStr;\n \n /// Configuration for converting Nushell [`Value`] to NUON data.\n ///\n@@ -330,11 +331,19 @@ fn value_to_string(\n all_rows.push(row);\n }\n \n- // Column widths = max of header and cell widths per column\n- let mut widths: Vec = col_names.iter().map(|h| h.len()).collect();\n+ // Column widths = max of header and cell widths per column.\n+ // Measured in terminal display width via unicode-width: double-width\n+ // cells (e.g. CJK) count 2, zero-width combining marks count 0.\n+ // The padding below fills each cell to that same display width, so\n+ // the column lines up on the terminal; measuring in bytes made a\n+ // column too wide whenever its longest cell had multi-byte characters.\n+ let mut widths: Vec = col_names\n+ .iter()\n+ .map(|h| UnicodeWidthStr::width(h.as_str()))\n+ .collect();\n for row in &all_rows {\n for (i, cell) in row.iter().enumerate() {\n- widths[i] = widths[i].max(cell.len());\n+ widths[i] = widths[i].max(UnicodeWidthStr::width(cell.as_str()));\n }\n }\n \n@@ -345,12 +354,17 @@ fn value_to_string(\n let mut out = String::new();\n for (i, item) in items.iter().enumerate() {\n if i < num_cols - 1 {\n- let _ = write!(\n- out,\n- \"{: = col_names.iter().map(|h| h.chars().count()).collect();\n```\n\nThis is bug 6 in `crates/nuon/spec/bugs_to_fix.md`, whose entry I have ticked as that file asks. The spec asks for one measure on both sides, which is what this does.\n\n**Terminal display width, and why not.** Display width is the measure that would make CJK and ASCII line up visually, and it is available — `unicode-width` is already a workspace dependency and `nu-term-grid` uses it. I deliberately did not use it here. Display width is\n...[truncated]"}, "repo": "nushell/nushell", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "b500a2ee95134f81d74da7911d7378dd2853d042", "candidate_corpus": {"base_commit": "b500a2ee95134f81d74da7911d7378dd2853d042", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/classic/tests/union.test.ts"], "given_files": ["packages/zod/src/v4/core/schemas.ts"]}, "id": "a5a7726d02369b3d73a23e5e", "metadata": {"changed_files": ["packages/zod/src/v4/classic/tests/union.test.ts", "packages/zod/src/v4/core/schemas.ts"], "created_at": "2026-10-12T18:22:58Z", "fix_commit": "680d19f7d1e042e55934209caeb79bc843b94f44", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 11, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/classic/tests/union.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"packages/zod/src/v4/classic/tests/union.test.ts": ["packages", "union", "zod"]}}, "merged_at": "2026-10-13T18:16:29Z", "pr": 6662, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/colinhacks/zod/pull/6662"}, "query": {"anchor_diff": "@@ -2466,10 +2466,14 @@ function handleUnionResults(results: ParsePayload[], final: ParsePayload, inst:\n }\n }\n \n- const nonaborted = results.filter((r) => !util.aborted(r));\n- if (nonaborted.length === 1) {\n- final.value = nonaborted[0].value;\n- return nonaborted[0];\n+ let matched = results.filter((r) => !util.aborted(r));\n+ // failing that, an option only checks rejected still matched the input's type\n+ if (!matched.length) {\n+ matched = results.filter((r) => !r.aborted && r.issues.every((iss) => iss.continue !== undefined));\n+ }\n+ if (matched.length === 1) {\n+ final.value = matched[0].value;\n+ return matched[0];\n }\n \n final.issues.push({", "anchor_file": "packages/zod/src/v4/core/schemas.ts", "intent": "fix(v4): report a union option that only checks rejected\n\nA union reports an option's own issues again when a size bound was the only thing that rejected it. Since #6652, `.max()`, `.length()` and `.size()` reject an oversized array, set or map before its elements are parsed. That issue aborts so no later check reads the unparsed value, and the union read the abort as a type mismatch and fell back to `invalid_union`.\n\n```ts\nz.union([z.array(z.string()).max(2), z.string()]).safeParse([\"a\", \"b\", \"c\"]);\n// 4.6.5 and now: too_big from the array option\n// 4.6.6: invalid_union\n```\n\nThe abort in the size check stays. Instead, when no option can continue, the union now falls back to the options whose issues all came from checks, and reports that option when it is the only one. This reads the `continue` flag every issue already carries: `true` or `false` when a check raised it, unset when the type didn't match.\n\nThis only ever turns an `invalid_union` into a single option's issues. Every case that already reported one option still does. Besides the regression, a few other options that a check stopped outright are now reported directly, where they used to give `invalid_union`:\n\n- `z.int()`: `z.union([z.int(), z.string()]).safeParse(1.5)` now reports \"expected int, received number\".\n- An option rejected by `.refine(..., { abort: true })` or a `fatal: true` issue now reports that issue.\n\n| axis | result |\n| --- | --- |\n| runtime | Only reached when every option fails. When all of them fail on type, ~4–5% slower (1033 → 1078 ns median, 6 interleaved rounds). The capped case is 2.3x faster since it no longer builds `invalid_union`. Successful parses are unchanged. |\n| memory | Unchanged. Nothing is added to schema instances. |\n| bundle | `zod/mini` union fixture +26 B gzipped (3778 →\n...[truncated]"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "b500a2ee95134f81d74da7911d7378dd2853d042", "candidate_corpus": {"base_commit": "b500a2ee95134f81d74da7911d7378dd2853d042", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/locales/es.ts", "packages/zod/src/v4/locales/fr.ts", "packages/zod/src/v4/locales/hr.ts", "packages/zod/src/v4/locales/lt.ts"], "given_files": ["packages/zod/src/v4/locales/he.ts"]}, "id": "7a611f936a88663df09df2c2", "metadata": {"changed_files": ["packages/zod/src/v4/core/tests/locales/he.test.ts", "packages/zod/src/v4/core/tests/locales/parity.test.ts", "packages/zod/src/v4/locales/es.ts", "packages/zod/src/v4/locales/fr.ts", "packages/zod/src/v4/locales/he.ts", "packages/zod/src/v4/locales/hr.ts", "packages/zod/src/v4/locales/lt.ts"], "created_at": "2026-10-12T18:21:02Z", "fix_commit": "40a5dba080b065cc430e5b0e64a8058d68c1660d", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 1, "deletions": 0, "is_test": false, "path": "packages/zod/src/v4/locales/es.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 1, "deletions": 0, "is_test": false, "path": "packages/zod/src/v4/locales/fr.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 1, "deletions": 0, "is_test": false, "path": "packages/zod/src/v4/locales/hr.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 17, "deletions": 0, "is_test": false, "path": "packages/zod/src/v4/locales/lt.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"packages/zod/src/v4/locales/es.ts": ["locales", "packages", "zod"], "packages/zod/src/v4/locales/fr.ts": ["locales", "packages", "zod"], "packages/zod/src/v4/locales/hr.ts": ["locales", "packages", "zod"], "packages/zod/src/v4/locales/lt.ts": ["locales", "packages", "zod"]}}, "merged_at": "2026-10-13T18:15:58Z", "pr": 6661, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/colinhacks/zod/pull/6661"}, "query": {"anchor_diff": "@@ -31,6 +31,7 @@ const error: () => errors.$ZodErrorMap = () => {\n file: { unit: \"בייטים\", shortLabel: \"קטן\", longLabel: \"גדול\" },\n array: { unit: \"פריטים\", shortLabel: \"קטן\", longLabel: \"גדול\" },\n set: { unit: \"פריטים\", shortLabel: \"קטן\", longLabel: \"גדול\" },\n+ map: { unit: \"פריטים\", shortLabel: \"קטן\", longLabel: \"גדול\" },\n number: { unit: \"\", shortLabel: \"קטן\", longLabel: \"גדול\" }, // no unit\n };\n \n@@ -150,9 +151,9 @@ const error: () => errors.$ZodErrorMap = () => {\n return `גדול מדי: ${subject} צריך להיות ${comparison}`;\n }\n \n- if (issue.origin === \"array\" || issue.origin === \"set\") {\n- // Natural Hebrew for arrays and sets\n- const verb = issue.origin === \"set\" ? \"צריכה\" : \"צריך\";\n+ if (issue.origin === \"array\" || issue.origin === \"set\" || issue.origin === \"map\") {\n+ // Natural Hebrew for arrays, sets and maps\n+ const verb = typeEntry(issue.origin)?.gender === \"f\" ? \"צריכה\" : \"צריך\";\n const comparison = issue.inclusive\n ? `${issue.maximum} ${sizing?.unit ?? \"\"} או פחות`\n : `פחות מ-${issue.maximum} ${sizing?.unit ?? \"\"}`;\n@@ -182,9 +183,9 @@ const error: () => errors.$ZodErrorMap = () => {\n return `קטן מדי: ${subject} צריך להיות ${comparison}`;\n }\n \n- if (issue.origin === \"array\" || issue.origin === \"set\") {\n- // Natural Hebrew for arrays and sets\n- const verb = issue.origin === \"set\" ? \"צריכה\" : \"צריך\";\n+ if (issue.origin === \"array\" || issue.origin === \"set\" || issue.origin === \"map\") {\n+ // Natural Hebrew for arrays, sets and maps\n+ const verb = typeEntry(issue.origin)?.gender === \"f\" ? \"צריכה\" : \"צריך\";\n \n // Special case for singular (minimum === 1)\n if (issue.minimum === 1 && issue.inclusive) {", "anchor_file": "packages/zod/src/v4/locales/he.ts", "intent": "fix(locales): add Sizable.map to es, fr, he, hr and lt, and check Sizable parity from source\n\nFixes #6657.\n\n`es`, `fr`, `he`, `hr` and `lt` had no `map` entry in `Sizable`, so `z.map()` size errors dropped their unit (`se esperaba que mapa fuera <=1`, and `lt` appended `undefined`). Each now copies its `set` entry, the same convention #6427 used. Hebrew also routes maps through its array/set phrasing (\"should contain N items\"), taking the verb's gender from its type table.\n\n#6427 touched all five files and added a parity test for exactly this, which passed anyway: its sentinel probe only sees a gap when a locale's size fallback echoes the raw origin, and these five render it as a translated noun (`mapa`), a placeholder (`valeur`), a capitalized word, or a label-table entry. `Sizable` is now checked against each locale's source instead; the `FormatDictionary` probe is unchanged, since every locale echoes an unknown format. Run against the old locale files, the new check reports exactly these five.\n\nThe `lt` trailing `undefined` for number, bigint and date (#6655) is a separate fix.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nfix(locales): add Sizable.map to es, fr, he, hr and lt, and check Sizable parity from source"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "b500a2ee95134f81d74da7911d7378dd2853d042", "candidate_corpus": {"base_commit": "b500a2ee95134f81d74da7911d7378dd2853d042", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/locales/es.ts", "packages/zod/src/v4/locales/fr.ts", "packages/zod/src/v4/locales/hr.ts", "packages/zod/src/v4/locales/he.ts"], "given_files": ["packages/zod/src/v4/locales/lt.ts"]}, "id": "b2ed5caf2c83f5446460af00", "metadata": {"changed_files": ["packages/zod/src/v4/core/tests/locales/he.test.ts", "packages/zod/src/v4/core/tests/locales/parity.test.ts", "packages/zod/src/v4/locales/es.ts", "packages/zod/src/v4/locales/fr.ts", "packages/zod/src/v4/locales/he.ts", "packages/zod/src/v4/locales/hr.ts", "packages/zod/src/v4/locales/lt.ts"], "created_at": "2026-10-12T18:21:02Z", "fix_commit": "40a5dba080b065cc430e5b0e64a8058d68c1660d", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 1, "deletions": 0, "is_test": false, "path": "packages/zod/src/v4/locales/es.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 1, "deletions": 0, "is_test": false, "path": "packages/zod/src/v4/locales/fr.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 1, "deletions": 0, "is_test": false, "path": "packages/zod/src/v4/locales/hr.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 7, "deletions": 6, "is_test": false, "path": "packages/zod/src/v4/locales/he.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"packages/zod/src/v4/locales/es.ts": ["locales", "packages", "zod"], "packages/zod/src/v4/locales/fr.ts": ["locales", "packages", "zod"], "packages/zod/src/v4/locales/he.ts": ["locales", "packages", "zod"], "packages/zod/src/v4/locales/hr.ts": ["locales", "packages", "zod"]}}, "merged_at": "2026-10-13T18:15:58Z", "pr": 6661, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/colinhacks/zod/pull/6661"}, "query": {"anchor_diff": "@@ -95,6 +95,23 @@ const error: () => errors.$ZodErrorMap = () => {\n },\n },\n },\n+ map: {\n+ unit: {\n+ one: \"elementą\",\n+ few: \"elementus\",\n+ many: \"elementų\",\n+ },\n+ verb: {\n+ smaller: {\n+ inclusive: \"turi turėti ne daugiau kaip\",\n+ notInclusive: \"turi turėti mažiau kaip\",\n+ },\n+ bigger: {\n+ inclusive: \"turi turėti ne mažiau kaip\",\n+ notInclusive: \"turi turėti daugiau kaip\",\n+ },\n+ },\n+ },\n };\n \n function getSizing(", "anchor_file": "packages/zod/src/v4/locales/lt.ts", "intent": "fix(locales): add Sizable.map to es, fr, he, hr and lt, and check Sizable parity from source\n\nFixes #6657.\n\n`es`, `fr`, `he`, `hr` and `lt` had no `map` entry in `Sizable`, so `z.map()` size errors dropped their unit (`se esperaba que mapa fuera <=1`, and `lt` appended `undefined`). Each now copies its `set` entry, the same convention #6427 used. Hebrew also routes maps through its array/set phrasing (\"should contain N items\"), taking the verb's gender from its type table.\n\n#6427 touched all five files and added a parity test for exactly this, which passed anyway: its sentinel probe only sees a gap when a locale's size fallback echoes the raw origin, and these five render it as a translated noun (`mapa`), a placeholder (`valeur`), a capitalized word, or a label-table entry. `Sizable` is now checked against each locale's source instead; the `FormatDictionary` probe is unchanged, since every locale echoes an unknown format. Run against the old locale files, the new check reports exactly these five.\n\nThe `lt` trailing `undefined` for number, bigint and date (#6655) is a separate fix.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nfix(locales): add Sizable.map to es, fr, he, hr and lt, and check Sizable parity from source"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "b500a2ee95134f81d74da7911d7378dd2853d042", "candidate_corpus": {"base_commit": "b500a2ee95134f81d74da7911d7378dd2853d042", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/tests/compile.test.ts", "packages/zod/src/v4/classic/tests/record.test.ts"], "given_files": ["packages/zod/src/v4/core/schemas.ts"]}, "id": "03f0c66f49b201481ae91caa", "metadata": {"changed_files": ["packages/zod/src/v4/classic/tests/record.test.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/tests/compile.test.ts"], "created_at": "2026-10-12T17:57:46Z", "fix_commit": "311cd74b2765ff7c7b58add60e37c5a0ea7a1972", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 8, "deletions": 5, "is_test": false, "path": "packages/zod/src/v4/core/compile.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 10, "deletions": 2, "is_test": true, "path": "packages/zod/src/v4/core/tests/compile.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 16, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/classic/tests/record.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"packages/zod/src/v4/classic/tests/record.test.ts": ["packages", "record", "zod"], "packages/zod/src/v4/core/compile.ts": ["packages", "zod"], "packages/zod/src/v4/core/tests/compile.test.ts": ["packages", "zod"]}}, "merged_at": "2026-10-13T18:15:16Z", "pr": 6660, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/colinhacks/zod/pull/6660"}, "query": {"anchor_diff": "@@ -3360,7 +3360,6 @@ export const $ZodRecord: core.$constructor<$ZodRecord> = /*@__PURE__*/ core.$con\n let unrecognized!: string[];\n // Reflect.ownKeys for Symbol-key support; filter non-enumerable to match z.object()\n for (const key of Reflect.ownKeys(input)) {\n- if (key === \"__proto__\") continue;\n if (!Object.prototype.propertyIsEnumerable.call(input, key)) continue;\n let keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);\n if (keyResult instanceof Promise) {\n@@ -3381,8 +3380,8 @@ export const $ZodRecord: core.$constructor<$ZodRecord> = /*@__PURE__*/ core.$con\n \n if (keyResult.issues.length) {\n if (def.mode === \"loose\") {\n- // Pass through unchanged\n- payload.value[key] = input[key];\n+ // pass through unchanged, except __proto__, which would replace the result prototype\n+ if (key !== \"__proto__\") payload.value[key] = input[key];\n } else if (values) {\n unrecognized = unrecognized ?? [];\n unrecognized.push(key as string);\n@@ -3400,9 +3399,9 @@ export const $ZodRecord: core.$constructor<$ZodRecord> = /*@__PURE__*/ core.$con\n continue;\n }\n \n- // the guard above tests the raw input key, but the key schema can normalize an ordinary key into __proto__; re-check the key we actually write under\n+ // never write an input __proto__, even renamed, nor a key normalized into __proto__\n const outKey = keyResult.value as PropertyKey;\n- if (outKey === \"__proto__\") continue;\n+ if (key === \"__proto__\" || outKey === \"__proto__\") continue;\n \n const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx);", "anchor_file": "packages/zod/src/v4/core/schemas.ts", "intent": "fix(v4): run a record's key schema on an own __proto__ key\n\nFixes #6641.\n\nA record whose key schema is a constraint — a refine, a regex, a `z.partialRecord` enum — skipped an own `__proto__` input key before the key schema ran, so a JSON body carrying `__proto__` passed records that reject every other bad key. The key now goes through the key schema like any other and is reported as `invalid_key` (or `unrecognized_keys` for a partial enum) when it fails. It is still never written to the output, even when the key schema accepts or renames it, so the stripping from #6386 is unchanged. This matches `.strict()` since #6221 and the exhaustive `z.record(z.enum())` path, which already reported it.\n\nThe compiled path gets the same change, and a loose record still drops the key rather than passing it through. Bundle size and record parse throughput are unchanged within noise.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nfix(v4): run a record's key schema on an own __proto__ key"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "b500a2ee95134f81d74da7911d7378dd2853d042", "candidate_corpus": {"base_commit": "b500a2ee95134f81d74da7911d7378dd2853d042", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/tests/compile.test.ts", "packages/zod/src/v4/classic/tests/record.test.ts"], "given_files": ["packages/zod/src/v4/core/compile.ts"]}, "id": "f5cc16bc275863c20d75d9ec", "metadata": {"changed_files": ["packages/zod/src/v4/classic/tests/record.test.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/tests/compile.test.ts"], "created_at": "2026-10-12T17:57:46Z", "fix_commit": "311cd74b2765ff7c7b58add60e37c5a0ea7a1972", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 4, "deletions": 5, "is_test": false, "path": "packages/zod/src/v4/core/schemas.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 10, "deletions": 2, "is_test": true, "path": "packages/zod/src/v4/core/tests/compile.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 16, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/classic/tests/record.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"packages/zod/src/v4/classic/tests/record.test.ts": ["packages", "record", "zod"], "packages/zod/src/v4/core/schemas.ts": ["packages", "zod"], "packages/zod/src/v4/core/tests/compile.test.ts": ["compile", "packages", "zod"]}}, "merged_at": "2026-10-13T18:15:16Z", "pr": 6660, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/colinhacks/zod/pull/6660"}, "query": {"anchor_diff": "@@ -2027,13 +2027,15 @@ function generateRecordCheck(doc: Doc, ctx: CompileContext, schema: SomeType, ac\n `if (${outKeyVar} === INVALID && typeof ${kVar} === \"string\" && ${numericConst}.test(${kVar})) ${outKeyVar} = ${keyFast}(Number(${kVar}));`\n );\n if (isLoose) {\n- // A loose record keeps a key its schema rejects, copying the value across unvalidated rather than failing the parse.\n- d.write(`if (${outKeyVar} === INVALID) { ${outputVar}[${kVar}] = ${accessor}[${kVar}]; continue; }`);\n+ // A loose record keeps a key its schema rejects, copying the value across unvalidated rather than failing the parse, except __proto__, which would replace the output prototype.\n+ d.write(\n+ `if (${outKeyVar} === INVALID) { if (${kVar} !== \"__proto__\") ${outputVar}[${kVar}] = ${accessor}[${kVar}]; continue; }`\n+ );\n } else {\n d.write(`if (${outKeyVar} === INVALID) return INVALID;`);\n }\n- // The guard above tested the input key, but the schema can normalize an ordinary key into __proto__; re-check the one actually written under.\n- d.write(`if (${outKeyVar} === \"__proto__\") continue;`);\n+ // never write an input __proto__, even renamed, nor a key normalized into __proto__\n+ d.write(`if (${kVar} === \"__proto__\" || ${outKeyVar} === \"__proto__\") continue;`);\n // Read once: the raw expression would be evaluated again by the output write below, so an accessor could return an unvalidated second value.\n const valueVar = newVar(ctx);\n d.write(`const ${valueVar} = ${accessor}[${kVar}];`);\n@@ -2050,6 +2052,7 @@ function generateRecordCheck(doc: Doc, ctx: CompileContext, schema: SomeType, ac\n accessor,\n kVar,\n (d) => {\n+ d.write(`if (${kVar} === \"__proto__\") continue;`);\n d.write(`const ${valVar} = ${accessor}[${kVar}];`);\n const valOutput = compileChild(d, ctx, def.valueType, valVar);\n d.write(`${outputVar}[${kVar}] = ${valOutput};`);\n@@ -2078,7 +2081,7 @@ function emitOwnKeys(\n doc.write(`for (let ${iVar} = 0; ${iVar} < ${keysVar}.length; ${iVar}++) {`);\n doc.indented((d) => {\n d.write(`const ${kVar} = ${keysVar}[${iVar}];`);\n- d.write(`if (${kVar} === \"__proto__\" || !${propIsEnumerableConst}.call(${accessor}, ${kVar})) continue;`);\n+ d.write(`if (!${propIsEnumerableConst}.call(${accessor}, ${kVar})) continue;`);\n body(d);\n });\n doc.write(`}`);", "anchor_file": "packages/zod/src/v4/core/compile.ts", "intent": "fix(v4): run a record's key schema on an own __proto__ key\n\nFixes #6641.\n\nA record whose key schema is a constraint — a refine, a regex, a `z.partialRecord` enum — skipped an own `__proto__` input key before the key schema ran, so a JSON body carrying `__proto__` passed records that reject every other bad key. The key now goes through the key schema like any other and is reported as `invalid_key` (or `unrecognized_keys` for a partial enum) when it fails. It is still never written to the output, even when the key schema accepts or renames it, so the stripping from #6386 is unchanged. This matches `.strict()` since #6221 and the exhaustive `z.record(z.enum())` path, which already reported it.\n\nThe compiled path gets the same change, and a loose record still drops the key rather than passing it through. Bundle size and record parse throughput are unchanged within noise.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nfix(v4): run a record's key schema on an own __proto__ key"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "0b216ef674e297ebe41d8bf902262e56f8755822", "candidate_corpus": {"base_commit": "0b216ef674e297ebe41d8bf902262e56f8755822", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/classic/tests/array.test.ts", "packages/zod/src/v4/classic/tests/set.test.ts"], "given_files": ["packages/zod/src/v4/core/util.ts"]}, "id": "0a69c8467467fa31f7a6ecdf", "metadata": {"changed_files": ["packages/zod/src/v4/classic/tests/array.test.ts", "packages/zod/src/v4/classic/tests/map.test.ts", "packages/zod/src/v4/classic/tests/set.test.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/util.ts"], "created_at": "2026-10-07T16:21:53Z", "fix_commit": "e06a510b6fc1e6e28e3201fd116ca2a76212f6be", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 9, "deletions": 0, "is_test": false, "path": "packages/zod/src/v4/core/compile.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 31, "deletions": 0, "is_test": false, "path": "packages/zod/src/v4/core/schemas.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 27, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/classic/tests/array.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 6, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/classic/tests/set.test.ts", "signals": ["path_token_overlap", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"packages/zod/src/v4/classic/tests/array.test.ts": ["array", "classic", "packages", "zod"], "packages/zod/src/v4/classic/tests/set.test.ts": ["classic", "packages", "set", "zod"], "packages/zod/src/v4/core/compile.ts": ["packages", "zod"], "packages/zod/src/v4/core/schemas.ts": ["schemas", "packages", "zod"]}}, "merged_at": "2026-10-09T19:50:22Z", "pr": 6652, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/colinhacks/zod/pull/6652"}, "query": {"anchor_diff": "@@ -935,6 +935,19 @@ export function unwrapMessage(message: string | { message: string } | undefined\n }\n \n /* A check holds no link back to the schema it is attached to — the same check instance is shared by every clone of that schema — so the owner is stamped onto the issues a check just raised, at the only point where both are in scope. Runs on the failure path only; `start` is the issue count from before the check ran. \n+/** The leading size checks of `defChecks` that set an upper bound, each paired with it. */\n+export function sizeCaps(defChecks: checks.$ZodCheck[] | undefined): [number, checks.$ZodCheck][] {\n+ const caps: [number, checks.$ZodCheck][] = [];\n+ for (const ch of defChecks ?? []) {\n+ const d = ch._zod.def as any;\n+ // a later check may rewrite the value\n+ if (!/_(length|size)$|_equals$/.test(d.check)) break;\n+ const max = d.maximum ?? d.length ?? d.size;\n+ if (max >= 0) caps.push([max, ch]);\n+ }\n+ return caps;\n+}\n+\n export function attachSchema(issues: errors.$ZodRawIssue[], start: number, inst: schemas.$ZodType): void {\n for (let i = start; i < issues.length; i++) {\n (issues[i] as any).schema ??= inst;", "anchor_file": "packages/zod/src/v4/core/util.ts", "intent": "fix(v4): check array, set and map size bounds before parsing elements\n\n`.max()`, `.length()` and `.size()` on arrays, sets and maps now reject an oversized input before any element is parsed. The bound used to run after the walk, so it bounded nothing: `z.array(z.string().uuid()).max(100)` given a million numbers built 1,000,001 issues before it reported `too_big`.\n\n```ts\nz.array(z.string().uuid()).max(100).safeParse(Array(1_000_000).fill(0));\n// one too_big issue in under a millisecond, was 1,000,001 issues in ~450 ms\n```\n\nOnly size checks that come before every other check take part, since something like `.overwrite()` can shrink the value first. The early rejection aborts, so a later `.refine()` never sees elements that weren't parsed, and an oversized input reports just the `too_big` issue rather than its element issues too. The compiled path gets the same check ahead of its loop. Unbounded containers are unchanged.\n\n| axis | result |\n| --- | --- |\n| runtime | The check wraps `parse` only on schemas that carry an upper bound, so an unbounded container runs the same code as before. `z.array(z.string()).max(100)` over 10 items: 65.9 → 67.4 ns (+1–3%, interleaved, but taken at load 10–20). Construction within noise. |\n| memory | Unbounded: unchanged. Bounded: +121 B per schema (3421 → 3542) for the wrapper closure. |\n| bundle | `zod/mini` array fixture +243 B gzipped (3311 → 3554, +7.3%), +227 with a `maxLength` check. Classic array +215 (+1.0%). Bundles without an array, set or map pay nothing (`zod-mini-object` unchanged). |\n\nPutting the check inside the existing parse closure was smaller (~190 B) but pushed it past V8's inlining budget: `z.array(z.string()).max(n)` parses went 58 → 71 ns.\n\nFixes #6643\n\nfix(v4): check array, set and map size bounds before parsing ele\n...[truncated]"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "0b216ef674e297ebe41d8bf902262e56f8755822", "candidate_corpus": {"base_commit": "0b216ef674e297ebe41d8bf902262e56f8755822", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/util.ts", "packages/zod/src/v4/classic/tests/set.test.ts", "packages/zod/src/v4/classic/tests/map.test.ts"], "given_files": ["packages/zod/src/v4/core/schemas.ts"]}, "id": "1b2cf28a63aab36c5d4e934a", "metadata": {"changed_files": ["packages/zod/src/v4/classic/tests/array.test.ts", "packages/zod/src/v4/classic/tests/map.test.ts", "packages/zod/src/v4/classic/tests/set.test.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/core/util.ts"], "created_at": "2026-10-07T16:21:53Z", "fix_commit": "e06a510b6fc1e6e28e3201fd116ca2a76212f6be", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 9, "deletions": 0, "is_test": false, "path": "packages/zod/src/v4/core/compile.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 13, "deletions": 0, "is_test": false, "path": "packages/zod/src/v4/core/util.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 6, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/classic/tests/set.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 7, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/classic/tests/map.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"packages/zod/src/v4/classic/tests/map.test.ts": ["classic", "map", "packages", "zod"], "packages/zod/src/v4/classic/tests/set.test.ts": ["classic", "packages", "set", "zod"], "packages/zod/src/v4/core/compile.ts": ["packages", "zod"], "packages/zod/src/v4/core/util.ts": ["util", "packages", "zod"]}}, "merged_at": "2026-10-09T19:50:22Z", "pr": 6652, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/colinhacks/zod/pull/6652"}, "query": {"anchor_diff": "@@ -1844,6 +1844,34 @@ export interface $ZodArrayInternals extends _$Zod\n \n export interface $ZodArray extends $ZodType> {}\n \n+// an oversized container fails its leading size checks before any element is parsed\n+function capSize(inst: $ZodType, size: (input: any) => number): void {\n+ const caps = util.sizeCaps(inst._zod.def.checks);\n+ if (!caps.length) return;\n+ const cap = Math.min(...caps.map((c) => c[0]));\n+ const parse = inst._zod.parse;\n+ inst._zod.parse = (payload, ctx) => {\n+ const n = size(payload.value);\n+ if (n > cap && !ctx?.skipChecks && ctx?.direction !== \"backward\") {\n+ for (const [max, ch] of util.sizeCaps(inst._zod.def.checks)) {\n+ if (n > max && ch._zod.def.when!(payload)) {\n+ const start = payload.issues.length;\n+ ch._zod.check(payload as ParsePayload);\n+ // the value is still the raw input, so no later check may read it\n+ (payload.issues[start] as { continue?: boolean }).continue = false;\n+ util.attachSchema(payload.issues, start, inst);\n+ return payload;\n+ }\n+ }\n+ }\n+ return parse(payload, ctx);\n+ };\n+}\n+\n+const arraySize = (input: unknown): number => (Array.isArray(input) ? input.length : -1);\n+const mapSize = (input: unknown): number => (input instanceof Map ? input.size : -1);\n+const setSize = (input: unknown): number => (input instanceof Set ? input.size : -1);\n+\n function handleArrayResult(result: ParsePayload, final: ParsePayload, index: number) {\n if (result.issues.length) {\n final.issues.push(...util.prefixIssues(index, result.issues));\n@@ -1899,6 +1927,7 @@ export const $ZodArray: core.$constructor<$ZodArray> = /*@__PURE__*/ core.$const\n \n return payload; //handleArrayResultsAsync(parseResults, final);\n };\n+ capSize(inst, arraySize);\n });\n \n //////////////////////////////////////////\n@@ -3483,6 +3512,7 @@ export const $ZodMap: core.$constructor<$ZodMap> = /*@__PURE__*/ core.$construct\n if (proms.length) return Promise.all(proms).then(() => payload);\n return payload;\n };\n+ capSize(inst, mapSize);\n });\n \n function handleMapResult(\n@@ -3585,6 +3615,7 @@ export const $ZodSet: core.$constructor<$ZodSet> = /*@__PURE__*/ core.$construct\n if (proms.length) return Promise.all(proms).then(() => payload);\n return payload;\n };\n+ capSize(inst, setSize);\n });\n \n function handleSetResult(result: ParsePayload, final: ParsePayload>) {", "anchor_file": "packages/zod/src/v4/core/schemas.ts", "intent": "fix(v4): check array, set and map size bounds before parsing elements\n\n`.max()`, `.length()` and `.size()` on arrays, sets and maps now reject an oversized input before any element is parsed. The bound used to run after the walk, so it bounded nothing: `z.array(z.string().uuid()).max(100)` given a million numbers built 1,000,001 issues before it reported `too_big`.\n\n```ts\nz.array(z.string().uuid()).max(100).safeParse(Array(1_000_000).fill(0));\n// one too_big issue in under a millisecond, was 1,000,001 issues in ~450 ms\n```\n\nOnly size checks that come before every other check take part, since something like `.overwrite()` can shrink the value first. The early rejection aborts, so a later `.refine()` never sees elements that weren't parsed, and an oversized input reports just the `too_big` issue rather than its element issues too. The compiled path gets the same check ahead of its loop. Unbounded containers are unchanged.\n\n| axis | result |\n| --- | --- |\n| runtime | The check wraps `parse` only on schemas that carry an upper bound, so an unbounded container runs the same code as before. `z.array(z.string()).max(100)` over 10 items: 65.9 → 67.4 ns (+1–3%, interleaved, but taken at load 10–20). Construction within noise. |\n| memory | Unbounded: unchanged. Bounded: +121 B per schema (3421 → 3542) for the wrapper closure. |\n| bundle | `zod/mini` array fixture +243 B gzipped (3311 → 3554, +7.3%), +227 with a `maxLength` check. Classic array +215 (+1.0%). Bundles without an array, set or map pay nothing (`zod-mini-object` unchanged). |\n\nPutting the check inside the existing parse closure was smaller (~190 B) but pushed it past V8's inlining budget: `z.array(z.string()).max(n)` parses went 58 → 71 ns.\n\nFixes #6643\n\nfix(v4): check array, set and map size bounds before parsing ele\n...[truncated]"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "d2b135cfb7a3582b9eb515756b9166bcb9521f4a", "candidate_corpus": {"base_commit": "d2b135cfb7a3582b9eb515756b9166bcb9521f4a", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/classic/tests/properties.test.ts"], "given_files": ["packages/zod/src/v4/classic/schemas.ts"]}, "id": "3f1f1d63e9e1e2665f326b67", "metadata": {"changed_files": ["packages/zod/src/v4/classic/schemas.ts", "packages/zod/src/v4/classic/tests/properties.test.ts"], "created_at": "2026-09-13T18:25:35Z", "fix_commit": "56222cd1532c07bcb91b67df529cab4c0a215330", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 19, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/classic/tests/properties.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"packages/zod/src/v4/classic/tests/properties.test.ts": ["classic", "packages", "properties", "zod"]}}, "merged_at": "2026-09-13T18:30:47Z", "pr": 6600, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/colinhacks/zod/pull/6600"}, "query": {"anchor_diff": "@@ -2841,7 +2841,8 @@ type ZodInstanceOfParams = core.Params<\n \n // ZodInstanceOf\n export interface ZodInstanceOf extends ZodCustom {\n- properties(\n+ // the shape is keyed off the instance type, so keys autocomplete and a schema that can't accept the property's type is an error. Methods are excluded: every object literal inherits Object.prototype.toString, which would otherwise collide with the constraint's own toString entry and reject every shape.\n+ properties }>(\n shape: Shape,\n params?: string | core.$ZodCheckPropertiesParams\n ): ZodInstanceOf>;", "anchor_file": "packages/zod/src/v4/classic/schemas.ts", "intent": "feat(instanceof): key the .properties() shape off the instance type\n\nThe method took any `$ZodShape`, so `z.instanceof(File).properties({ nmae: z.string() })` compiled, and so did a schema that can't accept the property's type. The shape is now a mapped type over `keyof T`, so the keys autocomplete and both of those are errors.\n\nMethods are excluded from the shape, which was the one real obstacle here. Every object literal inherits `Object.prototype.toString`, so a constraint carrying `URL`'s own `toString` entry rejects every shape literal passed to it.\n\nType-only — the emitted JS is byte-identical, so runtime, memory and bundle are all unchanged and only the `.d.ts` grows. It does tighten a public signature: a shape key outside the instance type, or on a method, now fails to compile where it previously didn't.\n\nOn the Zod Mini side: the spread form already rejects an unknown key and a wrong property type in both builds, since the check's input type demands the properties exist on the base. What it doesn't get is autocomplete, because the shape literal is written before any contextual type reaches it. That would need either a new exported helper, which costs bytes in every mini bundle, or a change to the shared `.check()` signature.\n\nRefs #6598\n\nfeat(instanceof): key the .properties() shape off the instance type"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "1c51cbe0fe23d09f8d520b31487d50a01588fae5", "candidate_corpus": {"base_commit": "1c51cbe0fe23d09f8d520b31487d50a01588fae5", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/classic/tests/discriminated-unions.test.ts"], "given_files": ["packages/zod/src/v4/core/schemas.ts"]}, "id": "49395310cb8817e052da1859", "metadata": {"changed_files": ["packages/docs/content/api.mdx", "packages/zod/src/v4/classic/tests/discriminated-unions.test.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/schemas.ts"], "created_at": "2026-09-09T17:44:01Z", "fix_commit": "b12aa523e7e2617c4296cccf9b24d6558ed23e95", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "packages/zod/src/v4/core/compile.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 112, "deletions": 6, "is_test": true, "path": "packages/zod/src/v4/classic/tests/discriminated-unions.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"packages/zod/src/v4/classic/tests/discriminated-unions.test.ts": ["classic", "discriminated", "packages", "unions", "zod"], "packages/zod/src/v4/core/compile.ts": ["packages", "zod"]}}, "merged_at": "2026-09-09T19:20:34Z", "pr": 6582, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/colinhacks/zod/pull/6582"}, "query": {"anchor_diff": "@@ -2600,7 +2600,7 @@ export interface $ZodDiscriminatedUnionInternals<\n def: $ZodDiscriminatedUnionDef;\n propValues: util.PropValues;\n bag: util.LoosePartial<{\n- optionsMap: Map;\n+ optionsMap: Map;\n }>;\n }\n \n@@ -2624,7 +2624,7 @@ export type $DiscriminatedOption): Map {\n+ const map = new Map();\n+ for (const option of def.options as readonly $ZodType[]) {\n+ const values = option._zod.propValues?.[def.discriminator];\n+ if (!values || values.size === 0)\n+ throw new Error(`Invalid discriminated union option at index \"${def.options.indexOf(option)}\"`);\n+ for (const value of values) {\n+ if (map.has(value)) {\n+ if (value !== undefined) throw new Error(`Duplicate discriminator value \"${String(value)}\"`);\n+ // keep the collision marked so a later member cannot reclaim it\n+ map.set(value, null);\n+ } else {\n+ map.set(value, option);\n+ }\n+ }\n+ }\n+ return map;\n }\n \n export interface $ZodDiscriminatedUnion<\n@@ -2661,10 +2677,12 @@ export const $ZodDiscriminatedUnion: core.$constructor<$ZodDiscriminatedUnion> =\n const _super = inst._zod.parse;\n util.defineLazyInternal(inst, \"propValues\", (zod) => {\n const propValues: util.PropValues = {};\n+ let undefinedCount = 0;\n for (const option of zod.def.options) {\n const pv = option._zod.propValues;\n if (!pv || Object.keys(pv).length === 0)\n throw new Error(`Invalid discriminated union option at index \"${zod.def.options.indexOf(option)}\"`);\n+ if (pv[zod.def.discriminator]?.has(undefined)) undefinedCount++;\n for (const [k, v] of Object.entries(pv!)) {\n if (!Object.prototype.hasOwnProperty.call(propValues, k)) {\n util.assignProp(propValues, k, new Set());\n@@ -2674,6 +2692,7 @@ export const $ZodDiscriminatedUnion: core.$constructor<$ZodDiscriminatedUnion> =\n }\n }\n }\n+ if (!zod.def.unionFallback && undefinedCount > 1) propValues[zod.def.discriminator]?.delete(undefined);\n return propValues;\n });\n \n@@ -2685,22 +2704,7 @@ export const $ZodDiscriminatedUnion: core.$constructor<$ZodDiscriminatedUnion> =\n }\n });\n \n- const disc = util.cached(() => {\n- const opts = def.options;\n- const map: Map = new Map();\n- for (const o of opts) {\n- const values = o._zod.propValues?.[def.discriminator];\n- if (!values || values.size === 0)\n- throw new Error(`Invalid discriminated union option at index \"${def.options.indexOf(o)}\"`);\n- for (const v of values) {\n- if (map.has(v)) {\n- throw new Error(`Duplicate discriminator value \"${String(v)}\"`);\n- }\n- map.set(v, o);\n- }\n- }\n- return map;\n- });\n+ const disc = util.cached(() => discriminatorMap(def));\n \n inst._zod.parse = (payload, ctx) => {\n const input = payload.value;\n@@ -2715,8 +2719,10 @@ export const $ZodDiscriminatedUnion: core.$constructor<$ZodDiscriminatedUnion> =\n return payload;\n }\n \n- const opt = disc.value.get(input?.[def.discriminator] as any);\n- if (opt) {\n+ const value = input?.[def.discriminator];\n+ const opt = disc.value.get(value as util.Primitive);\n+ // forward metadata cannot choose an encoder for an absent tag\n+ if (opt && (value !== undefined || ctx.direction !== \"backward\")) {\n return opt._zod.run(payload, ctx) as any;\n }\n \n@@ -2733,7 +2739,7 @@ export const $ZodDiscriminatedUnion: core.$constructor<$ZodDiscriminatedUnion> =\n errors: [],\n note: \"No matching discriminator\",\n discriminator: def.discriminator,\n- options: Array.from(disc.value.keys()),\n+ options: Array.from(disc.value.keys()).filter((value) => disc.value.get(value) !== null),\n input,\n path: [def.discriminator],\n inst,", "anchor_file": "packages/zod/src/v4/core/schemas.ts", "intent": "fix: preserve unique tags with defaulted discriminators\n\nPreserve explicitly tagged parsing when multiple discriminated-union members have defaulted tags. A shared map builder marks colliding `undefined` values as ambiguous; missing tags fail validation, while unique tags retain direct dispatch. Other duplicate values remain schema errors.\n\nThere are no schema-type checks, wrapper walks, new options, or new instance properties. The lookup helper uses the same map builder and rejects ambiguous lookup. Nested unions omit an unroutable `undefined` from their discriminator metadata; backward encoding of `undefined` uses the existing union fallback so forward-only metadata cannot select the wrong sibling. Defined tags retain their encoding fast path. The compiler keeps its existing interpreter fallback for collisions rather than introducing a second dispatch policy.\n\nLocal build, lint, resolution, integration, and the full suite pass, including 8,243 tests on each of TypeScript 5.5.4, 6.0.3, and 7.0.2. Plain-Node ESM/CJS probes pass for both classic and Mini. The encoding regression has synchronous and asynchronous coverage, and the API reference documents ambiguous lookup.\n\n| Measurement | Base → change |\n| --- | --- |\n| Parse, median of ten process minima | 38.06 → 38.44 ns (+1.0%) |\n| Defined-tag encode, median of ten process minima | 48.21 → 48.03 ns (-0.4%) |\n| Construction, median of ten process minima | 802.6 → 804.1 ns (+0.2%) |\n| Classic discriminated-union fixture, gzip | 21,159 → 21,248 B (+89 B) |\n| Mini discriminated-union fixture, gzip | 5,238 → 5,339 B (+101 B) |\n| Classic / Mini object-only fixtures | unchanged |\n| Fresh two-member union, retained heap | 9,136 → 9,136 B in repeated isolated measurements |\n| Shared-member union, unparsed / parsed | approximate\n...[truncated]"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "1c51cbe0fe23d09f8d520b31487d50a01588fae5", "candidate_corpus": {"base_commit": "1c51cbe0fe23d09f8d520b31487d50a01588fae5", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/classic/tests/discriminated-unions.test.ts"], "given_files": ["packages/zod/src/v4/core/compile.ts"]}, "id": "58e3ba50c49b107ee4cc123e", "metadata": {"changed_files": ["packages/docs/content/api.mdx", "packages/zod/src/v4/classic/tests/discriminated-unions.test.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/schemas.ts"], "created_at": "2026-09-09T17:44:01Z", "fix_commit": "b12aa523e7e2617c4296cccf9b24d6558ed23e95", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 34, "deletions": 28, "is_test": false, "path": "packages/zod/src/v4/core/schemas.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 112, "deletions": 6, "is_test": true, "path": "packages/zod/src/v4/classic/tests/discriminated-unions.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"packages/zod/src/v4/classic/tests/discriminated-unions.test.ts": ["classic", "discriminated", "packages", "unions", "zod"], "packages/zod/src/v4/core/schemas.ts": ["packages", "zod"]}}, "merged_at": "2026-09-09T19:20:34Z", "pr": 6582, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/colinhacks/zod/pull/6582"}, "query": {"anchor_diff": "@@ -1869,7 +1869,7 @@ function generateDiscriminatedUnionCheck(\n throw new ZodCompileUnsupportedError(\"discriminated union option without static discriminator values\");\n }\n \n- // Two options claiming one value are not discriminable, and the branch chain below would silently give it to the first. Declining to compile hands that back to the interpreter, whose own map build reports it.\n+ // let the interpreter handle collisions instead of compiling first-match dispatch\n for (const value of values) {\n if (claimed.has(value)) {\n throw new ZodCompileUnsupportedError(`duplicate discriminator value ${String(value)}`);", "anchor_file": "packages/zod/src/v4/core/compile.ts", "intent": "fix: preserve unique tags with defaulted discriminators\n\nPreserve explicitly tagged parsing when multiple discriminated-union members have defaulted tags. A shared map builder marks colliding `undefined` values as ambiguous; missing tags fail validation, while unique tags retain direct dispatch. Other duplicate values remain schema errors.\n\nThere are no schema-type checks, wrapper walks, new options, or new instance properties. The lookup helper uses the same map builder and rejects ambiguous lookup. Nested unions omit an unroutable `undefined` from their discriminator metadata; backward encoding of `undefined` uses the existing union fallback so forward-only metadata cannot select the wrong sibling. Defined tags retain their encoding fast path. The compiler keeps its existing interpreter fallback for collisions rather than introducing a second dispatch policy.\n\nLocal build, lint, resolution, integration, and the full suite pass, including 8,243 tests on each of TypeScript 5.5.4, 6.0.3, and 7.0.2. Plain-Node ESM/CJS probes pass for both classic and Mini. The encoding regression has synchronous and asynchronous coverage, and the API reference documents ambiguous lookup.\n\n| Measurement | Base → change |\n| --- | --- |\n| Parse, median of ten process minima | 38.06 → 38.44 ns (+1.0%) |\n| Defined-tag encode, median of ten process minima | 48.21 → 48.03 ns (-0.4%) |\n| Construction, median of ten process minima | 802.6 → 804.1 ns (+0.2%) |\n| Classic discriminated-union fixture, gzip | 21,159 → 21,248 B (+89 B) |\n| Mini discriminated-union fixture, gzip | 5,238 → 5,339 B (+101 B) |\n| Classic / Mini object-only fixtures | unchanged |\n| Fresh two-member union, retained heap | 9,136 → 9,136 B in repeated isolated measurements |\n| Shared-member union, unparsed / parsed | approximate\n...[truncated]"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "1c51cbe0fe23d09f8d520b31487d50a01588fae5", "candidate_corpus": {"base_commit": "1c51cbe0fe23d09f8d520b31487d50a01588fae5", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/jsr.json"], "given_files": ["packages/zod/src/v4/locales/index.ts"]}, "id": "cd94dc393b48d43cebff2431", "metadata": {"changed_files": ["packages/docs/content/error-customization.mdx", "packages/zod/jsr.json", "packages/zod/src/v4/core/tests/locales/tg.test.ts", "packages/zod/src/v4/locales/index.ts", "packages/zod/src/v4/locales/tg.ts"], "created_at": "2026-09-09T17:36:07Z", "fix_commit": "574d480fb443d3fd396efbcb8230f3dfee4a2cd2", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 1, "deletions": 0, "is_test": false, "path": "packages/zod/jsr.json", "signals": ["path_token_overlap", "shared_config_or_schema"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"packages/zod/jsr.json": ["jsr", "packages", "zod"]}}, "merged_at": "2026-09-09T17:53:25Z", "pr": 6581, "ripple_relation": ["path_token_overlap", "shared_config_or_schema"], "source_pr": "https://github.com/colinhacks/zod/pull/6581"}, "query": {"anchor_diff": "@@ -49,6 +49,7 @@ export { default as sk } from \"./sk.js\";\n export { default as sl } from \"./sl.js\";\n export { default as sv } from \"./sv.js\";\n export { default as ta } from \"./ta.js\";\n+export { default as tg } from \"./tg.js\";\n export { default as th } from \"./th.js\";\n export { default as tk } from \"./tk.js\";\n export { default as tr } from \"./tr.js\";", "anchor_file": "packages/zod/src/v4/locales/index.ts", "intent": "feat(locales): add Tajik\n\nAdds the Tajik locale from @ismoil77’s branch, preserving author credit. Includes the locale export, JSR subpath, documentation entry, and coverage for each error branch.\n\nCloses #6578.\n\nfeat(lang): add Tajik (`tg`) locale\n\ntest(locales): cover Tajik error branches\n\nfix(locales): clarify Tajik discriminator value message"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "36f17960d1defca5d0896d9424f4e1059fbbf081", "candidate_corpus": {"base_commit": "36f17960d1defca5d0896d9424f4e1059fbbf081", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/classic/external.ts", "packages/zod/src/v4/mini/external.ts", "packages/zod/src/v4/core/tests/compile.test.ts"], "given_files": ["packages/zod/src/v4/core/compile.ts"]}, "id": "729191a0e7df318d60ca3b17", "metadata": {"changed_files": ["packages/zod/src/v4/classic/external.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/tests/compile.test.ts", "packages/zod/src/v4/mini/external.ts"], "created_at": "2026-09-09T05:16:08Z", "fix_commit": "213ee75d2ad6e41508587c3fab8246967f006993", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 2, "deletions": 0, "is_test": false, "path": "packages/zod/src/v4/classic/external.ts", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 2, "deletions": 0, "is_test": false, "path": "packages/zod/src/v4/mini/external.ts", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 80, "deletions": 2, "is_test": true, "path": "packages/zod/src/v4/core/tests/compile.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"packages/zod/src/v4/classic/external.ts": ["classic", "packages", "zod"], "packages/zod/src/v4/core/tests/compile.test.ts": ["compile", "packages", "zod"], "packages/zod/src/v4/mini/external.ts": ["mini", "packages", "zod"]}}, "merged_at": "2026-09-09T16:31:49Z", "pr": 6575, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/colinhacks/zod/pull/6575"}, "query": {"anchor_diff": "@@ -126,53 +126,9 @@ export interface CompileOptions {\n export function compile(schema: T, options?: CompileOptions): T {\n try {\n const parser = compileFn(schema);\n- const clone = util.clone(schema as any) as T;\n-\n- // Capture the source-of-truth runtime eagerly. If schema._zod.run is itself a shim installed by global-mode (`__originalRun` set), unwrap past it. Otherwise capturing the live property lazily would let a later self- replacement of schema._zod.run feed our wrapper back into itself.\n- const liveRun = schema._zod.run as ((p: ParsePayload, c: ParseContextInternal) => any) & {\n- __originalRun?: (p: ParsePayload, c: ParseContextInternal) => any;\n- };\n- const originalRun = liveRun.__originalRun ?? liveRun;\n-\n- // Delegate to the *original* schema's run on bypass/fallback (not the\n- // clone's). The original closed over its own `inst` at construction time;\n- // issue payloads use that reference to derive things like the class name\n- // for `z.instanceof(Test)`. Calling the clone's freshly-initialized run\n- // would push issues with `inst === clone`, producing diverging error\n- // messages from the original schema.\n- const wrapped = (payload: ParsePayload, ctx: ParseContextInternal): any => {\n- if (\n- ctx?.async ||\n- ctx?.direction === \"backward\" ||\n- ctx?.skipChecks ||\n- (ctx as Record | undefined)?.[FALLBACK_FLAG]\n- ) {\n- return originalRun(payload, ctx);\n- }\n-\n- // A memoized back-edge: only the runtime can close a reference cycle, and a transform on one must raise $ZodCyclicError from its own parse.\n- if (ctx && isBackEdge(ctx, payload.value)) {\n- return originalRun(payload, ctx);\n- }\n-\n- const out = parser(payload.value);\n- if (out !== INVALID) {\n- payload.value = out;\n- return payload;\n- }\n- // Mark this parse as runtime-driven: under global mode every nested schema carries its own compiled wrapper, and without the flag the parent's runtime fallback re-enters each child's fast path, running user callbacks a third time on invalid input.\n- if (ctx) (ctx as Record)[FALLBACK_FLAG] = true;\n- return originalRun(payload, ctx);\n- };\n- // Let later compiles of (or through) this run unwrap to the true runtime — both the global shim and repeated z.compile calls rely on this. The bag also carries the parser and the validator, so the standalone validate can skip the payload and wrapper on the happy path.\n- (wrapped as { __originalRun?: typeof originalRun }).__originalRun = originalRun;\n- clone._zod.bag.fallbackRun = originalRun;\n+ const clone = withParser(schema, parser);\n+ // withParser leaves the parser as its own validator; the generated assert-only variant is better when we have one\n clone._zod.bag.validator = compileValidator(schema, parser as CompiledFn);\n- clone._zod.run = wrapped;\n-\n- // The fast parse/safeParse closures fall back through the source schema's methods. If the source is shim- or wrapper-managed, those methods route into a compiled run and would execute user callbacks a third time on invalid input — the plain method → wrapper path is exactly 2x, so skip.\n- if (!liveRun.__originalRun) installCompiledUserMethods(clone, schema, parser);\n-\n return clone;\n } catch (err) {\n if (options?.strict) throw err;\n@@ -181,6 +137,68 @@ export function compile(schema: T, options?: CompileOptions)\n }\n }\n \n+/**\n+ * Install an already-generated parser as a schema's fast path. Returns a clone; the original is\n+ * unchanged.\n+ *\n+ * The parser takes the input and returns the parsed value, or `INVALID` to hand the parse to the\n+ * runtime. It must be synchronous and forward-direction, and it must build fresh output rather than\n+ * return its input — Zod cannot check either, and a wrong *success* is returned to the caller as-is.\n+ *\n+ * `compile()` is the ordinary entry point. This is for a build-time or native compiler that produces\n+ * a parser where `new Function` is unavailable.\n+ */\n+export function withParser(schema: T, parser: (input: unknown) => core.output | INVALID): T {\n+ // generated code never receives the parse context, so only the runtime can close a reference cycle; compileFn refuses these too\n+ if (isRecursiveSchema(schema as any)) {\n+ throw new ZodCompileUnsupportedError(\"a schema whose subtree contains a reference cycle\");\n+ }\n+ const clone = util.clone(schema as any) as T;\n+\n+ // Capture the source-of-truth runtime eagerly. If schema._zod.run is itself a shim installed by global-mode (`__originalRun` set), unwrap past it. Otherwise capturing the live property lazily would let a later self- replacement of schema._zod.run feed our wrapper back into itself.\n+ const liveRun = schema._zod.run as ((p: ParsePayload, c: ParseContextInternal) => any) & {\n+ __originalRun?: (p: ParsePayload, c: ParseContextInternal) => any;\n+ };\n+ const originalRun = liveRun.__originalRun ?? liveRun;\n+\n+ // Delegate to the *original* schema's run on bypass/fallback, not the clone's. The original closed over its own `inst` at construction time, and issue payloads use that reference to derive things like the class name for `z.instanceof(Test)`; calling the clone's freshly-initialized run would push issues with `inst =\n+ const wrapped = (payload: ParsePayload, ctx: ParseContextInternal): any => {\n+ if (\n+ ctx?.async ||\n+ ctx?.direction === \"backward\" ||\n+ ctx?.skipChecks ||\n+ (ctx as Record | undefined)?.[FALLBACK_FLAG]\n+ ) {\n+ return originalRun(payload, ctx);\n+ }\n+\n+ // A memoized back-edge: only the runtime can close a reference cycle, and a transform on one must raise $ZodCyclicError from its own parse.\n+ if (ctx && isBackEdge(ctx, payload.value)) {\n+ return originalRun(payload, ctx);\n+ }\n+\n+ const out = parser(payload.value);\n+ if (out !== INVALID) {\n+ payload.value = out;\n+ return payload;\n+ }\n+ // Mark this parse as runtime-driven: under global mode every nested schema carries its own compiled wrapper, and without the flag the parent's runtime fallback re-enters each child's fast path, running user callbacks a third time on invalid input.\n+ if (ctx) (ctx as Record)[FALLBACK_FLAG] = true;\n+ return originalRun(payload, ctx);\n+ };\n+ // Let later compiles of (or through) this run unwrap to the true runtime — both the global shim and repeated z.compile calls rely on this. The bag also carries the parser and the validator, so the standalone validate can skip the payload and wrapper on the happy path.\n+ (wrapped as { __originalRun?: typeof originalRun }).__originalRun = originalRun;\n+ clone._zod.bag.fallbackRun = originalRun;\n+ // a supplied parser answers `validate` too: one implementation means parse and validate cannot disagree, and its undefined `definite` keeps the runtime re-parse on every rejection\n+ clone._zod.bag.validator = parser as CompiledFn;\n+ clone._zod.run = wrapped;\n+\n+ // The fast parse/safeParse closures fall back through the source schema's methods. If the source is shim- or wrapper-managed, those methods route into a compiled run and would execute user callbacks a third time on invalid input — the plain method → wrapper path is exactly 2x, so skip.\n+ if (!liveRun.__originalRun) installCompiledUserMethods(clone, schema, parser as CompiledFn>);\n+\n+ return clone;\n+}\n+\n function installCompiledUserMethods(\n target: T,\n source: T,", "anchor_file": "packages/zod/src/v4/core/compile.ts", "intent": "feat(compile): add z.withParser for externally generated parsers\n\nExports `z.withParser(schema, parser)` — the installer half of `compile()`, so a build-time or native compiler can supply the parser where `new Function` isn't available. `compile()` calls it, so the wrapper contract has one implementation.\n\nThe parser returns the parsed value or `INVALID`, which is now exported too. Zod keeps everything else: the clone, the async/backward/skip-check bypasses, the memoizer back-edge check, the fallback flag, and the runtime as the only source of `ZodError`s.\n\nTwo design calls worth flagging.\n\nA supplied parser is its own validator rather than getting a generated assert-only one. Reaching `compileValidator` pulls `compileFn` and the whole codegen into any bundle that imports `withParser` — measured at +7.4 KB gz on a classic fixture. It's also the better semantic: one implementation means `parse()` and `validate()` can't disagree, and an undefined `definite` keeps `validate`'s runtime re-parse on every rejection.\n\nThe recursion guard moves with the installer. A supplied parser skips `compileFn`, which is what refuses a schema whose subtree contains a cycle; generated code never receives the parse context, so only the runtime can close one. `isRecursiveSchema` needs no eval, so it runs on this path too.\n\nThree axes: parse-path runtime unchanged (the wrapper is byte-identical), construction +0.03% from the added structural walk (0.02 µs against 60.74 µs for a full `z.compile`), memory unchanged (same three fields on the bag), bundle −2 B gz on both `zod-object` and `zod-mini-object` fixtures — non-users pay nothing, and `withParser` alone bundles to 1.4 KB gz.\n\nRefs #6498.\n\nfeat(compile): add z.withParser for externally generated parsers\n\nrefactor(compile): type withParser's\n...[truncated]"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "cafbee4772ef481611fef6f5fb9ed9a1b9597069", "candidate_corpus": {"base_commit": "cafbee4772ef481611fef6f5fb9ed9a1b9597069", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/classic/tests/validate.test.ts"], "given_files": ["packages/zod/src/v4/classic/schemas.ts"]}, "id": "0406aeefdb0a3d42c034b793", "metadata": {"changed_files": ["packages/docs/content/basics.mdx", "packages/zod/src/v4/classic/schemas.ts", "packages/zod/src/v4/classic/tests/validate.test.ts"], "created_at": "2026-09-01T19:20:07Z", "fix_commit": "62e6624bc72c4882968ac4ea2c4281b1a99a7ad4", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 50, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/classic/tests/validate.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"packages/zod/src/v4/classic/tests/validate.test.ts": ["classic", "packages", "validate", "zod"]}}, "merged_at": "2026-09-01T20:18:21Z", "pr": 6547, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/colinhacks/zod/pull/6547"}, "query": {"anchor_diff": "@@ -78,6 +78,8 @@ export interface ZodType<\n data: unknown,\n params?: core.ParseContext\n ) => Promise>>;\n+ validate(data: unknown, params?: core.ParseContext): data is core.input;\n+ validateAsync(data: unknown, params?: core.ParseContext): Promise;\n \n // encoding/decoding\n encode(data: core.output, params?: core.ParseContext): core.input;\n@@ -310,6 +312,12 @@ export const ZodType: core.$constructor = /*@__PURE__*/ core.$construct\n set spa(value: ZodType[\"safeParseAsync\"]) {\n util.own(this, \"spa\", value);\n },\n+ validate(data, params) {\n+ return parse.validate(this, data, params);\n+ },\n+ validateAsync(data, params) {\n+ return parse.validateAsync(this, data, params);\n+ },\n encode: function _encode(data, params) {\n return parse.encode(this, data, params, { callee: _encode });\n },", "anchor_file": "packages/zod/src/v4/classic/schemas.ts", "intent": "feat(v4): add .validate() and .validateAsync() to Zod Classic\n\n`z.validate()` and `z.validateAsync()` shipped in 4.5 as top-level functions only. Classic reaches for methods everywhere else, so this adds `.validate()` and `.validateAsync()` to `ZodType` as thin delegates.\n\n```ts\nconst Player = z.object({ username: z.string(), xp: z.number() });\n\nif (Player.validate(data)) {\n data.username; // narrowed\n}\n```\n\nThe predicate lives on the interface, not in the member table — `util.ProtoOf` maps a type-predicate signature's `infer R` to plain `boolean`, so the implementation needs no cast. Narrowing goes to the schema's **input** type: `z.string().transform(s => s.length).validate(v)` narrows `v` to `string`, never `number`.\n\n`zod/mini` deliberately does not get these. It stays a top-level-function API, and a test pins that.\n\n## Three axes\n\n**Bundle** — the one that got worse. esbuild `--minify --conditions=@zod/source`, gzip -9, against a pristine `origin/main` worktree:\n\n| fixture | main | branch | delta |\n| --- | --- | --- | --- |\n| `zod-mini-boolean` / `-string` / `-object` / `-simple-object` / `-full` | — | — | **+0** |\n| `zod-boolean` | 17003 | 17177 | +174 |\n| `zod-string` | 21035 | 21224 | +189 |\n| `zod-object` | 25113 | 25288 | +175 |\n| `zod-full` | 25106 | 25286 | +180 |\n| `zod-named-import` | 89192 | 89220 | +28 |\n\nA prototype reference to `parse.validate` retains the validate implementation that a tree-shaken classic bundle used to drop; `zod.compile.fallback` and `zod.compile.invalid` go from absent to present. That is the same trade `encode`/`decode` already make, and it is unavoidable for a method form. `zod/mini` is byte-identical on every fixture, which is the line that matters most on this axis. The `packages/treeshake` ceilings cover mini only, so none\n...[truncated]"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "07917f4cb396646dff7a1364f9032a668b0d7eb4", "candidate_corpus": {"base_commit": "07917f4cb396646dff7a1364f9032a668b0d7eb4", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/core/parse.ts", "packages/treeshake/bundle-size.test.ts", "packages/zod/src/v4/classic/tests/validate.test.ts"], "given_files": ["packages/zod/src/v4/core/schemas.ts"]}, "id": "a07b2f2f886929f901dd7308", "metadata": {"changed_files": ["packages/bench/validate-abort-sweep.ts", "packages/treeshake/bundle-size.test.ts", "packages/zod/src/v4/classic/tests/validate.test.ts", "packages/zod/src/v4/core/parse.ts", "packages/zod/src/v4/core/schemas.ts"], "created_at": "2026-09-01T03:28:17Z", "fix_commit": "764ac59f1afc1a46e7ecc2d5e8e86c57b7d66164", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 6, "deletions": 2, "is_test": false, "path": "packages/zod/src/v4/core/parse.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 2, "deletions": 1, "is_test": true, "path": "packages/treeshake/bundle-size.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 317, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/classic/tests/validate.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"packages/treeshake/bundle-size.test.ts": ["packages"], "packages/zod/src/v4/classic/tests/validate.test.ts": ["packages", "validate", "zod"], "packages/zod/src/v4/core/parse.ts": ["parse", "packages", "zod"]}}, "merged_at": "2026-09-01T22:04:37Z", "pr": 6544, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/colinhacks/zod/pull/6544"}, "query": {"anchor_diff": "@@ -30,6 +30,8 @@ export interface ParseContextInternal ex\n readonly async?: boolean | undefined;\n readonly direction?: \"forward\" | \"backward\";\n readonly skipChecks?: boolean;\n+ /** Set only by `validate`/`validateAsync`. A container may stop before its next child, never inside one, so a map entry and a tuple's fixed items parse whole. */\n+ readonly abortEarly?: boolean;\n }\n \n /** Gives a container cycle support: `attach` wraps its parse, and `alloc` registers the object it builds into before any child is parsed so a reference back to the same input resolves to it. */\n@@ -1819,6 +1821,7 @@ export const $ZodArray: core.$constructor<$ZodArray> = /*@__PURE__*/ core.$const\n \n payload.value = memo ? memo.alloc(inst, payload, Array(input.length), ctx) : Array(input.length);\n const proms: Promise[] = [];\n+ const abortEarly = ctx?.abortEarly;\n for (let i = 0; i < input.length; i++) {\n const item = input[i];\n const result = def.element._zod.run(\n@@ -1833,6 +1836,8 @@ export const $ZodArray: core.$constructor<$ZodArray> = /*@__PURE__*/ core.$const\n proms.push(result.then((result) => handleArrayResult(result, payload, i)));\n } else {\n handleArrayResult(result, payload, i);\n+ // the element's payload is authoritative here, since handleArrayResult forwards every issue; an object's is not, because it drops a failed absent optional\n+ if (abortEarly && result.issues.length !== 0 && util.aborted(result)) break;\n }\n }\n \n@@ -2037,9 +2042,10 @@ function handleCatchall(\n proms: Promise[],\n input: any,\n payload: ParsePayload,\n- ctx: ParseContext,\n+ ctx: ParseContextInternal,\n def: ReturnType,\n- inst: $ZodObject\n+ inst: $ZodObject,\n+ abortEarly: boolean\n ) {\n const unrecognized: string[] = [];\n const keySet = def.keySet;\n@@ -2047,7 +2053,13 @@ function handleCatchall(\n const t = _catchall.def.type;\n const optin = _catchall.optin;\n const optout = _catchall.optout;\n+ // starts at 0, not the current length: the shape phase already ran and may have aborted\n+ let seen = 0;\n for (const key in input) {\n+ if (abortEarly && payload.issues.length !== seen) {\n+ if (util.aborted(payload, seen)) break;\n+ seen = payload.issues.length;\n+ }\n // Must precede the __proto__ branch: a declared key is not unrecognized, even though the shape loop deliberately strips __proto__ from the parsed output.\n if (keySet.has(key)) continue;\n // Don't copy an undeclared __proto__ into the result; assignment to a plain {} would replace the result prototype. But in strict mode it is still an unknown key, so report it before skipping.\n@@ -2146,8 +2158,14 @@ export const $ZodObject: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$con\n \n const proms: Promise[] = [];\n const shape = value.shape;\n+ const abortEarly = ctx?.abortEarly;\n+ let seen = payload.issues.length;\n \n for (const key of value.allKeys) {\n+ if (abortEarly && payload.issues.length !== seen) {\n+ if (util.aborted(payload, seen)) break;\n+ seen = payload.issues.length;\n+ }\n if (key === \"__proto__\") continue;\n const el = (shape as any)[key]!;\n const optin = el._zod.optin;\n@@ -2165,7 +2183,7 @@ export const $ZodObject: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$con\n return proms.length ? Promise.all(proms).then(() => payload) : payload;\n }\n \n- return handleCatchall(proms, input, payload, ctx, _normalized.value, inst);\n+ return handleCatchall(proms, input, payload, ctx, _normalized.value, inst, abortEarly === true);\n };\n });\n \n@@ -2188,12 +2206,18 @@ export const $ZodObjectJIT: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$\n \n const parseStr = (k: string) => `shape[${k}]._zod.run({ value: input[${k}], issues: [] }, ctx)`;\n \n- // Prefixes in place, like util.prefixIssues does for every interpreted path.\n+ // prefixes in place, like util.prefixIssues. newResult must land before the early return: a catchall runs after this and would otherwise write onto the caller's input\n const prefixStr = (id: string, k: string) => `\n+ let ${id}_ab = false;\n for (let i = 0; i < ${id}.issues.length; i++) {\n const iss = ${id}.issues[i];\n iss.path = iss.path ? [${k}, ...iss.path] : [${k}];\n payload.issues.push(iss);\n+ if (iss.continue !== true) ${id}_ab = true;\n+ }\n+ if (${id}_ab && ctx && ctx.abortEarly) {\n+ payload.value = newResult;\n+ return payload;\n }`;\n \n doc.write(`const input = payload.value;`);\n@@ -2245,6 +2269,10 @@ export const $ZodObjectJIT: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$\n input: undefined,\n path: [${k}]\n });\n+ if (ctx && ctx.abortEarly) {\n+ payload.value = newResult;\n+ return payload;\n+ }\n }\n \n if (${id}_present) {\n@@ -2305,7 +2333,7 @@ export const $ZodObjectJIT: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$\n payload = fastpass(payload, ctx);\n \n if (!catchall) return payload;\n- return handleCatchall([], input, payload, ctx, value, inst);\n+ return handleCatchall([], input, payload, ctx, value, inst, ctx?.abortEarly === true);\n }\n \n return superParse(payload, ctx);\n@@ -2968,6 +2996,9 @@ export const $ZodTuple: core.$constructor<$ZodTuple> = /*@__PURE__*/ core.$const\n \n // Run every item in parallel, collecting results into an indexed array. The post-processing in `handleTupleResults` walks them in order so it can decide whether an absent optional-output error can truncate the tail or must be reported to preserve required output.\n const itemResults: ParsePayload[] = new Array(items.length);\n+ // only tracked when there is a rest loop to skip\n+ const abortEarly = def.rest ? ctx?.abortEarly : undefined;\n+ let itemAborted = false;\n for (let i = 0; i < items.length; i++) {\n const r = items[i]._zod.run({ value: input[i], issues: [] }, ctx);\n if (r instanceof Promise) {\n@@ -2978,13 +3009,20 @@ export const $ZodTuple: core.$constructor<$ZodTuple> = /*@__PURE__*/ core.$const\n );\n } else {\n itemResults[i] = r;\n+ if (abortEarly && !itemAborted && r.issues.length) itemAborted = util.aborted(r);\n }\n }\n \n- if (def.rest) {\n+ // sound because rest is non-empty exactly when every fixed index is present, the one case handleTupleResults cannot discard an item's issues\n+ if (def.rest && !itemAborted) {\n let i = items.length - 1;\n const rest = input.slice(items.length);\n+ let seen = payload.issues.length;\n for (const el of rest) {\n+ if (abortEarly && payload.issues.length !== seen) {\n+ if (util.aborted(payload, seen)) break;\n+ seen = payload.issues.length;\n+ }\n i++;\n const result = def.rest._zod.run({ value: el, issues: [] }, ctx);\n if (result instanceof Promise) {\n@@ -3154,6 +3192,7 @@ export const $ZodRecord: core.$constructor<$ZodRecord> = /*@__PURE__*/ core.$con\n return payload;\n }\n \n+ // no guard in either loop below: a record's invalid_key aborts but an enclosing intersection can reconcile it, so a stopped loop hides keys the sibling does not own and the intersection then rejects nothing\n const proms: Promise[] = [];\n \n const values = def.keyType._zod.values;\n@@ -3358,8 +3397,14 @@ export const $ZodMap: core.$constructor<$ZodMap> = /*@__PURE__*/ core.$construct\n \n const proms: Promise[] = [];\n payload.value = memo ? memo.alloc(inst, payload, new Map(), ctx) : new Map();\n+ const abortEarly = ctx?.abortEarly;\n+ let seen = payload.issues.length;\n \n for (const [key, value] of input) {\n+ if (abortEarly && payload.issues.length !== seen) {\n+ if (util.aborted(pay\n...[truncated]", "anchor_file": "packages/zod/src/v4/core/schemas.ts", "intent": "perf(v4): settle z.validate on the first failure in parse order\n\nToday `z.validate()` walks the whole schema even after the answer is settled. On a 20-key object with a wrong value in the first key, it still parses the other 19 — the boolean was decided at key 0, and everything after it is work nobody reads.\n\nThis gives the runtime parse path an early exit and lets `validate` / `validateAsync` take it. Nothing else does, and there is no new public surface: the context field is internal, and the commented-out `abortEarly` on the public `ParseContext` stays commented out.\n\nThe asymmetry is what makes it safe. Reporting every issue and handing back a well-formed value is what `safeParse` owes its caller, so it can never stop early. A boolean is all `validate` returns, so the truncated value a stopped container leaves behind is never read by anyone.\n\n### The contract\n\nFirst failure in parse order wins. Once an aborting issue settles the boolean, the container stops before the next child it would have parsed, so a callback there never runs — exactly as if it were not in the schema:\n\n```ts\nconst schema = z.object({\n a: z.number(),\n b: z.string().transform(() => { throw new RangeError(); }),\n});\nschema.safeParse({ a: \"bad\", b: \"ok\" }); // throws: it walks the whole shape\nz.validate(schema, { a: \"bad\", b: \"ok\" }); // false: `a` settled it, `b` never ran\n```\n\nA throw that does happen still bubbles, unchanged. Nothing rejects before the callback below, so `validate` runs it and the exception is the caller's:\n\n```ts\nz.validate(z.object({ a: z.string().transform(boom), b: z.number() }), { a: \"ok\", b: \"bad\" }); // throws\n```\n\nThe stop lands between children, never inside one. A map entry parses its key and value together, and a tuple runs every fixed item before `handleTupleResul\n...[truncated]"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "07917f4cb396646dff7a1364f9032a668b0d7eb4", "candidate_corpus": {"base_commit": "07917f4cb396646dff7a1364f9032a668b0d7eb4", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/core/schemas.ts", "packages/zod/src/v4/classic/tests/validate.test.ts", "packages/treeshake/bundle-size.test.ts"], "given_files": ["packages/zod/src/v4/core/parse.ts"]}, "id": "c62736d11caa228b9a88f63f", "metadata": {"changed_files": ["packages/bench/validate-abort-sweep.ts", "packages/treeshake/bundle-size.test.ts", "packages/zod/src/v4/classic/tests/validate.test.ts", "packages/zod/src/v4/core/parse.ts", "packages/zod/src/v4/core/schemas.ts"], "created_at": "2026-09-01T03:28:17Z", "fix_commit": "764ac59f1afc1a46e7ecc2d5e8e86c57b7d66164", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 57, "deletions": 6, "is_test": false, "path": "packages/zod/src/v4/core/schemas.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 317, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/classic/tests/validate.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 2, "deletions": 1, "is_test": true, "path": "packages/treeshake/bundle-size.test.ts", "signals": ["path_token_overlap", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"packages/treeshake/bundle-size.test.ts": ["packages"], "packages/zod/src/v4/classic/tests/validate.test.ts": ["packages", "validate", "zod"], "packages/zod/src/v4/core/schemas.ts": ["schemas", "packages", "zod"]}}, "merged_at": "2026-09-01T22:04:37Z", "pr": 6544, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/colinhacks/zod/pull/6544"}, "query": {"anchor_diff": "@@ -153,7 +153,9 @@ function validateFallback(\n value: unknown,\n _ctx?: schemas.ParseContext\n ): boolean {\n- const ctx: schemas.ParseContextInternal = _ctx ? { ..._ctx, async: false } : { async: false };\n+ const ctx: schemas.ParseContextInternal = _ctx\n+ ? { ..._ctx, async: false, abortEarly: true }\n+ : { async: false, abortEarly: true };\n const fallbackRun = (schema._zod.bag as CompiledBag).fallbackRun;\n let result: unknown;\n if (fallbackRun) {\n@@ -177,7 +179,9 @@ export type $ValidateAsync = (\n \n // no fast path: the compiler keeps async parses on the runtime, because a promise-returning callback that is not declared async compiles to a throw\n export const validateAsync: $ValidateAsync = async (schema, value, _ctx) => {\n- const ctx: schemas.ParseContextInternal = _ctx ? { ..._ctx, async: true } : { async: true };\n+ const ctx: schemas.ParseContextInternal = _ctx\n+ ? { ..._ctx, async: true, abortEarly: true }\n+ : { async: true, abortEarly: true };\n let result: unknown = schema._zod.run({ value, issues: [] }, ctx);\n if (result instanceof Promise) result = await result;\n return (result as schemas.ParsePayload).issues.length === 0;", "anchor_file": "packages/zod/src/v4/core/parse.ts", "intent": "perf(v4): settle z.validate on the first failure in parse order\n\nToday `z.validate()` walks the whole schema even after the answer is settled. On a 20-key object with a wrong value in the first key, it still parses the other 19 — the boolean was decided at key 0, and everything after it is work nobody reads.\n\nThis gives the runtime parse path an early exit and lets `validate` / `validateAsync` take it. Nothing else does, and there is no new public surface: the context field is internal, and the commented-out `abortEarly` on the public `ParseContext` stays commented out.\n\nThe asymmetry is what makes it safe. Reporting every issue and handing back a well-formed value is what `safeParse` owes its caller, so it can never stop early. A boolean is all `validate` returns, so the truncated value a stopped container leaves behind is never read by anyone.\n\n### The contract\n\nFirst failure in parse order wins. Once an aborting issue settles the boolean, the container stops before the next child it would have parsed, so a callback there never runs — exactly as if it were not in the schema:\n\n```ts\nconst schema = z.object({\n a: z.number(),\n b: z.string().transform(() => { throw new RangeError(); }),\n});\nschema.safeParse({ a: \"bad\", b: \"ok\" }); // throws: it walks the whole shape\nz.validate(schema, { a: \"bad\", b: \"ok\" }); // false: `a` settled it, `b` never ran\n```\n\nA throw that does happen still bubbles, unchanged. Nothing rejects before the callback below, so `validate` runs it and the exception is the caller's:\n\n```ts\nz.validate(z.object({ a: z.string().transform(boom), b: z.number() }), { a: \"ok\", b: \"bad\" }); // throws\n```\n\nThe stop lands between children, never inside one. A map entry parses its key and value together, and a tuple runs every fixed item before `handleTupleResul\n...[truncated]"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "68aca3dc402c59f5c4e30322e83028389e44b8b5", "candidate_corpus": {"base_commit": "68aca3dc402c59f5c4e30322e83028389e44b8b5", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/core/json-schema-generator.ts", "packages/zod/src/v4/core/json-schema-processors.ts"], "given_files": ["packages/zod/src/v4/core/to-json-schema.ts"]}, "id": "b38e4d49f5d8ef418dd82a28", "metadata": {"changed_files": ["packages/zod/src/v4/core/json-schema-generator.ts", "packages/zod/src/v4/core/json-schema-processors.ts", "packages/zod/src/v4/core/tests/polyfill-collision.test.ts", "packages/zod/src/v4/core/to-json-schema.ts"], "created_at": "2026-08-31T22:18:04Z", "fix_commit": "18e71c71daff6e79ab8f00a48db252ccb340da1f", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 2, "deletions": 2, "is_test": false, "path": "packages/zod/src/v4/core/json-schema-generator.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 25, "deletions": 25, "is_test": false, "path": "packages/zod/src/v4/core/json-schema-processors.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"packages/zod/src/v4/core/json-schema-generator.ts": ["json", "packages", "schema", "zod"], "packages/zod/src/v4/core/json-schema-processors.ts": ["json", "packages", "processors", "schema", "zod"]}}, "merged_at": "2026-08-31T22:44:12Z", "pr": 6541, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/colinhacks/zod/pull/6541"}, "query": {"anchor_diff": "@@ -128,7 +128,7 @@ export interface ToJSONSchemaContext {\n * covers both passes in `finalize`: the ref flattening and the `$defs` build.\n *\n * The passes are valid only while nothing they read has changed, so both are cleared in\n- * `process()` when the map grows, and in `JSONSchemaGenerator.emit()`, which can also change\n+ * `processSchema()` when the map grows, and in `JSONSchemaGenerator.emit()`, which can also change\n * the `cycles` and `reused` they branch on.\n *\n * One case is deliberately not covered: an `override` callback that writes to\n@@ -209,7 +209,8 @@ export function handleUnrepresentable(\n return true;\n }\n \n-export function process(\n+// never rename this back to `process`: bundler polyfills inject a top-level `const process` that a lexical declaration of the same name collides with (#6397)\n+export function processSchema(\n schema: T,\n ctx: ToJSONSchemaContext,\n _params: ProcessParams = { path: [], schemaPath: [] }\n@@ -264,7 +265,7 @@ export function process(\n if (parent) {\n // Also set ref if processor didn't (for inheritance)\n if (!result.ref) result.ref = parent;\n- process(parent, ctx, params);\n+ processSchema(parent, ctx, params);\n ctx.seen.get(parent)!.isParent = true;\n }\n }\n@@ -289,6 +290,9 @@ export function process(\n return _result.schema;\n }\n \n+/** @deprecated Renamed to `processSchema`. An export alias declares no binding, so it is safe to keep. */\n+export { processSchema as process };\n+\n // Escape a reference token for use in a JSON Pointer fragment (RFC 6901): `~` becomes `~0` and `/` becomes `~1`. The `~` replacement must run first.\n function encodeJSONPointerSegment(segment: string): string {\n return segment.replace(/~/g, \"~0\").replace(/\\//g, \"~1\");\n@@ -832,7 +836,7 @@ export const createToJSONSchemaMethod =\n (schema: T, processors: Record = {}) =>\n (params?: ToJSONSchemaParams): ZodStandardJSONSchemaPayload => {\n const ctx = initializeContext({ ...params, processors });\n- process(schema, ctx);\n+ processSchema(schema, ctx);\n extractDefs(ctx, schema);\n return finalize(ctx, schema);\n };\n@@ -847,7 +851,7 @@ export const createStandardJSONSchemaMethod =\n (params?: StandardJSONSchemaMethodParams): JSONSchema.BaseSchema => {\n const { libraryOptions, target } = params ?? {};\n const ctx = initializeContext({ ...(libraryOptions ?? {}), target, io, processors });\n- process(schema, ctx);\n+ processSchema(schema, ctx);\n extractDefs(ctx, schema);\n return finalize(ctx, schema);\n };", "anchor_file": "packages/zod/src/v4/core/to-json-schema.ts", "intent": "Rename the JSON Schema `process` helper so bundler polyfills cannot collide\n\n`to-json-schema.ts` declares `export function process(...)` at module scope, and has shipped it since 4.2.0. A browser polyfill for node globals that lands as raw text in the bundle's top scope — an esbuild `banner`, a plugin that prepends a shim in `transform` — collides with it. The bundler appends its banner after renaming its own symbols, so it never sees the duplicate, and the browser is the first thing to read both declarations:\n\n```\nSyntaxError: Identifier 'process' has already been declared\n```\n\nRenamed to `processSchema`, with `process` kept as an export alias. An export specifier declares no local binding, so the old name stays importable from `zod/v4/core` without bringing the collision back. `JSONSchemaGenerator#process` is a class member rather than a top-level binding, so it is untouched, as are `processors`, `Processor` and `ProcessParams`.\n\nReproduced against the published 4.5.4 tarball with esbuild's `--banner:js`, and confirmed fixed. The reporter's own setup — Vite 5.4.14 dev with `NodeGlobalsPolyfillPlugin({ process: true })` — does not reproduce it: esbuild's `inject` is scope-aware, so it sees the conflict and renames Zod's declaration to `process2`. Something else in their build is injecting `process` as raw text, and the rename closes the whole class either way.\n\nBundle size is byte-identical, minified and gzipped, on classic and mini both with and without `toJSONSchema` reachable.\n\nFixes #6397\n\nRename the JSON Schema `process` helper so bundler polyfills cannot collide\n\nKeep `process` as an export alias of `processSchema`"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "69f2a7ff203e546e3a1350fb9152ace03ba0a6e6", "candidate_corpus": {"base_commit": "69f2a7ff203e546e3a1350fb9152ace03ba0a6e6", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/tests/compile.test.ts", "packages/zod/src/v4/classic/tests/validate.test.ts"], "given_files": ["packages/zod/src/v4/core/parse.ts"]}, "id": "3d6a58ebdec05d5156fbc406", "metadata": {"changed_files": ["packages/zod/src/v4/classic/tests/validate.test.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/parse.ts", "packages/zod/src/v4/core/tests/compile.test.ts", "wiki/compile.md"], "created_at": "2026-08-31T20:28:09Z", "fix_commit": "81ded9918fe39d51b232be72f23ba0d5fb6a837e", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 34, "deletions": 13, "is_test": false, "path": "packages/zod/src/v4/core/compile.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 21, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/core/tests/compile.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 189, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/classic/tests/validate.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"packages/zod/src/v4/classic/tests/validate.test.ts": ["packages", "validate", "zod"], "packages/zod/src/v4/core/compile.ts": ["compile", "packages", "zod"], "packages/zod/src/v4/core/tests/compile.test.ts": ["compile", "packages", "zod"]}}, "merged_at": "2026-08-31T21:47:08Z", "pr": 6538, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/colinhacks/zod/pull/6538"}, "query": {"anchor_diff": "@@ -115,7 +115,7 @@ const COMPILE_INVALID = /* @__PURE__ */ Symbol.for(\"zod.compile.invalid\");\n const COMPILE_FALLBACK = /* @__PURE__ */ Symbol.for(\"zod.compile.fallback\");\n \n interface CompiledBag {\n- validator?: (input: unknown) => unknown;\n+ validator?: ((input: unknown) => unknown) & { definite?: boolean | undefined };\n fallbackRun?: (payload: schemas.ParsePayload, ctx: schemas.ParseContextInternal) => unknown;\n }\n \n@@ -132,7 +132,11 @@ export const validate: $Validate = ((\n _ctx?: schemas.ParseContext\n ): boolean => {\n const validator = (schema._zod.bag as CompiledBag).validator;\n- if (validator !== undefined && validator(value) !== COMPILE_INVALID) return true;\n+ if (validator !== undefined) {\n+ if (validator(value) !== COMPILE_INVALID) return true;\n+ // a definite sentinel means the runtime would reject, so skip the re-parse; a ctx can still change the answer\n+ if (validator.definite === true && _ctx === undefined) return false;\n+ }\n return validateFallback(schema, value, _ctx);\n }) as $Validate;", "anchor_file": "packages/zod/src/v4/core/parse.ts", "intent": "perf: answer z.validate from the compiled fast path on invalid input\n\n`z.validate` on a compiled schema re-ran the entire schema through the interpreter whenever the compiled validator rejected, just to reach the verdict the fast path had already produced.\n\nOften that second pass is dead work, because the compiled `INVALID` already means the runtime would reject — which is why a union can read a branch's `INVALID` as a rejection. Codegen now tracks a `definite` flag and `validate` skips the interpreted pass only while it survives. A call that passes a parse context still takes the interpreted path, since a context can change the verdict.\n\nTwo things clear the flag. Any hoisted **user callback** — a refine, transform, custom predicate, catch value or lazy getter — clears it, because that callback can throw and generated code can reject an earlier sibling before ever reaching it, so the rejection is no longer proof that the interpreter would have rejected rather than thrown. A **runtime island**, an **intersection**, and a **record key whose own compile is not definite** clear it directly. User code reaches generated code through a single `addUserConstant` helper that clears the flag, so a generator added later cannot quietly miss it.\n\nWhat keeps the fast path is the callback-free subset: type, range and format checks, enums, literals, unions, and object, array and tuple members. That is the shape a type guard is usually asked about.\n\nCompiled parsing semantics are untouched. The transform case is why this is a flag rather than a throw in generated code: a transform handing back a thenable has to keep answering `INVALID`, because the interpreter's own union falls through to the next branch there instead of propagating, and `compile-differential` pins that.\n\nInvalid input\n...[truncated]"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "69f2a7ff203e546e3a1350fb9152ace03ba0a6e6", "candidate_corpus": {"base_commit": "69f2a7ff203e546e3a1350fb9152ace03ba0a6e6", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/core/parse.ts", "packages/zod/src/v4/core/tests/compile.test.ts", "packages/zod/src/v4/classic/tests/validate.test.ts"], "given_files": ["packages/zod/src/v4/core/compile.ts"]}, "id": "69b60e1d5e67e228c0f49a3b", "metadata": {"changed_files": ["packages/zod/src/v4/classic/tests/validate.test.ts", "packages/zod/src/v4/core/compile.ts", "packages/zod/src/v4/core/parse.ts", "packages/zod/src/v4/core/tests/compile.test.ts", "wiki/compile.md"], "created_at": "2026-08-31T20:28:09Z", "fix_commit": "81ded9918fe39d51b232be72f23ba0d5fb6a837e", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 6, "deletions": 2, "is_test": false, "path": "packages/zod/src/v4/core/parse.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 21, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/core/tests/compile.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 189, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/classic/tests/validate.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"packages/zod/src/v4/classic/tests/validate.test.ts": ["packages", "validate", "zod"], "packages/zod/src/v4/core/parse.ts": ["parse", "packages", "zod"], "packages/zod/src/v4/core/tests/compile.test.ts": ["compile", "packages", "zod"]}}, "merged_at": "2026-08-31T21:47:08Z", "pr": 6538, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/colinhacks/zod/pull/6538"}, "query": {"anchor_diff": "@@ -34,7 +34,11 @@ interface CompileFnOptions {\n assertOnly?: boolean | undefined;\n }\n \n-type CompiledFn = ((input: unknown) => T | INVALID) & { code?: string | undefined };\n+type CompiledFn = ((input: unknown) => T | INVALID) & {\n+ code?: string | undefined;\n+ /** False when this function's INVALID does not strictly mean \"the runtime would reject\". */\n+ definite?: boolean | undefined;\n+};\n \n /** Raised when the schema contains async refinements or transforms. Surfaces only under `compile(schema, { strict: true })`. */\n export class ZodCompileAsyncError extends Error {\n@@ -65,6 +69,8 @@ interface CompileContext {\n constants: Map;\n constantCounter: number;\n varCounter: number;\n+ /** Cleared when a construct can return INVALID for something the interpreter throws on, so `validate` keeps its fallback. */\n+ definite: boolean;\n }\n \n // Union of all check types we support in AOT compilation\n@@ -91,9 +97,9 @@ type SupportedCheck =\n * dropped. A schema the flag cannot express reuses the parser, which still answers correctly — it\n * just builds a value nothing reads.\n */\n-function compileValidator(schema: SomeType, parser: (input: unknown) => unknown): (input: unknown) => unknown {\n+function compileValidator(schema: SomeType, parser: CompiledFn): CompiledFn {\n try {\n- return compileFn(schema, { assertOnly: true }) as (input: unknown) => unknown;\n+ return compileFn(schema, { assertOnly: true }) as CompiledFn;\n } catch {\n return parser;\n }\n@@ -159,7 +165,7 @@ export function compile(schema: T, options?: CompileOptions)\n // Let later compiles of (or through) this run unwrap to the true runtime — both the global shim and repeated z.compile calls rely on this. The bag also carries the parser and the validator, so the standalone validate can skip the payload and wrapper on the happy path.\n (wrapped as { __originalRun?: typeof originalRun }).__originalRun = originalRun;\n clone._zod.bag.fallbackRun = originalRun;\n- clone._zod.bag.validator = compileValidator(schema, parser as (input: unknown) => unknown);\n+ clone._zod.bag.validator = compileValidator(schema, parser as CompiledFn);\n clone._zod.run = wrapped;\n \n // The fast parse/safeParse closures fall back through the source schema's methods. If the source is shim- or wrapper-managed, those methods route into a compiled run and would execute user callbacks a third time on invalid input — the plain method → wrapper path is exactly 2x, so skip.\n@@ -222,6 +228,7 @@ export function compileFn(schema: T, options?: CompileFnOpti\n constants: new Map(),\n constantCounter: 0,\n varCounter: 0,\n+ definite: true,\n };\n \n const doc = new Doc([\"input\"]);\n@@ -253,6 +260,7 @@ export function compileFn(schema: T, options?: CompileFnOpti\n if (options?.debug) {\n fn.code = fullCode;\n }\n+ fn.definite = ctx.definite;\n return fn;\n }\n \n@@ -266,6 +274,12 @@ function addConstant(ctx: CompileContext, value: unknown): string {\n return name;\n }\n \n+/** Hoists a user-supplied callback. Anything the schema's author wrote can throw, and generated code can reject an earlier sibling before ever reaching it, so this clears `definite` — a rejection is then no longer proof that the interpreter would have rejected rather than thrown. */\n+function addUserConstant(ctx: CompileContext, fn: unknown): string {\n+ ctx.definite = false;\n+ return addConstant(ctx, fn);\n+}\n+\n function newVar(ctx: CompileContext): string {\n return `v${ctx.varCounter++}`;\n }\n@@ -322,6 +336,8 @@ function compileChild(\n }\n \n function emitRuntimeIsland(doc: Doc, ctx: CompileContext, schema: SomeType, accessor: string): string {\n+ // an islanded child answers INVALID for an async run too, which the interpreter throws for\n+ ctx.definite = false;\n const schemaConst = addConstant(ctx, schema);\n const runConst = addConstant(ctx, runtimeRun);\n const outVar = newVar(ctx);\n@@ -626,7 +642,7 @@ function generateCustomRefineCheck(doc: Doc, ctx: CompileContext, check: CustomC\n if (isAsyncFunction(def.fn)) {\n throw new ZodCompileAsyncError(\"z.compile: async .refine() predicates are not supported\");\n }\n- const fnConst = addConstant(ctx, def.fn);\n+ const fnConst = addUserConstant(ctx, def.fn);\n const throwAsyncConst = addConstant(ctx, throwAsync);\n const resVar = newVar(ctx);\n doc.write(`const ${resVar} = ${fnConst}(${accessor});`);\n@@ -653,7 +669,7 @@ function generateCustomRefineCheck(doc: Doc, ctx: CompileContext, check: CustomC\n if (result instanceof Promise) throwAsync();\n return fakePayload.issues.length === 0 ? fakePayload.value : INVALID;\n };\n- const helperConst = addConstant(ctx, helperFn);\n+ const helperConst = addUserConstant(ctx, helperFn);\n const outVar = newVar(ctx);\n doc.write(`const ${outVar} = ${helperConst}(${accessor});`);\n doc.write(`if (${outVar} === INVALID) return INVALID;`);\n@@ -1833,6 +1849,8 @@ function literalEquality(ctx: CompileContext, accessor: string, value: unknown):\n \n function generateIntersectionCheck(doc: Doc, ctx: CompileContext, schema: SomeType, accessor: string): string {\n const def = schema._zod.def as unknown as { left: SomeType; right: SomeType };\n+ // An unmergeable merge, and a child failing before the merge is even reached, both return INVALID for a case the interpreter answers with a throw.\n+ ctx.definite = false;\n const leftOutput = compileChild(doc, ctx, def.left, accessor);\n const rightOutput = compileChild(doc, ctx, def.right, accessor);\n \n@@ -1912,7 +1930,10 @@ function generateRecordCheck(doc: Doc, ctx: CompileContext, schema: SomeType, ac\n // The runtime runs it against each own enumerable key and writes the value\n // under the key it produced, so compile it once and call it per key.\n const isLoose = (def as { mode?: string }).mode === \"loose\";\n- const keyFast = addConstant(ctx, compileFn(def.keyType));\n+ // the key compiles in its own context, so carry its verdict out: a key schema that can answer INVALID undecidably makes this validator undecidable too\n+ const keyFn = compileFn(def.keyType);\n+ if (keyFn.definite === false) ctx.definite = false;\n+ const keyFast = addConstant(ctx, keyFn);\n const numericConst = addConstant(ctx, regexes.number);\n const propIsEnumerableConst = addConstant(ctx, Object.prototype.propertyIsEnumerable);\n const outKeyVar = newVar(ctx);\n@@ -2027,7 +2048,7 @@ function generateTemplateLiteralCheck(doc: Doc, ctx: CompileContext, schema: Som\n function generateLazyCheck(doc: Doc, ctx: CompileContext, schema: SomeType, accessor: string): string {\n // For lazy schemas, we use a cached parser that falls back to runtime Zod parsing This handles recursive schemas correctly by avoiding infinite compilation loops\n const def = schema._zod.def as unknown as { getter: () => SomeType };\n- const getterConst = addConstant(ctx, def.getter);\n+ const getterConst = addUserConstant(ctx, def.getter);\n const cacheConst = addConstant(ctx, { parser: null as ((input: unknown) => unknown) | null });\n \n doc.write(`if (!${cacheConst}.parser) {`);\n@@ -2060,7 +2081,7 @@ function generatePipeCheck(doc: Doc, ctx: CompileContext, schema: SomeType, acce\n const inputOutput = generateCheck(doc, ctx, def.in, accessor);\n \n if (def.transform) {\n- // Apply transform and validate output. The transform may read its second `payload` argument (codec transforms like z.stringbool() push issues there) so wrap the call in a helper that spoofs a payload. Pushed issues signal INVALID and the wrapper falls back to the runtime.\n+ // Apply transform and validate output. The transform may read its second `payload` argument (codec transforms like z.stringbool() push issues there) so wrap the call in a helper that spoofs a payload. Pushed issues signal INVALID and the wrapper falls back to the runtime, and a plain function handing back\n...[truncated]", "anchor_file": "packages/zod/src/v4/core/compile.ts", "intent": "perf: answer z.validate from the compiled fast path on invalid input\n\n`z.validate` on a compiled schema re-ran the entire schema through the interpreter whenever the compiled validator rejected, just to reach the verdict the fast path had already produced.\n\nOften that second pass is dead work, because the compiled `INVALID` already means the runtime would reject — which is why a union can read a branch's `INVALID` as a rejection. Codegen now tracks a `definite` flag and `validate` skips the interpreted pass only while it survives. A call that passes a parse context still takes the interpreted path, since a context can change the verdict.\n\nTwo things clear the flag. Any hoisted **user callback** — a refine, transform, custom predicate, catch value or lazy getter — clears it, because that callback can throw and generated code can reject an earlier sibling before ever reaching it, so the rejection is no longer proof that the interpreter would have rejected rather than thrown. A **runtime island**, an **intersection**, and a **record key whose own compile is not definite** clear it directly. User code reaches generated code through a single `addUserConstant` helper that clears the flag, so a generator added later cannot quietly miss it.\n\nWhat keeps the fast path is the callback-free subset: type, range and format checks, enums, literals, unions, and object, array and tuple members. That is the shape a type guard is usually asked about.\n\nCompiled parsing semantics are untouched. The transform case is why this is a flag rather than a throw in generated code: a transform handing back a thenable has to keep answering `INVALID`, because the interpreter's own union falls through to the next branch there instead of propagating, and `compile-differential` pins that.\n\nInvalid input\n...[truncated]"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "68a609ac9b9516e6fe84e3558f17ce16b1032bef", "candidate_corpus": {"base_commit": "68a609ac9b9516e6fe84e3558f17ce16b1032bef", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/core/json-schema-processors.ts", "packages/zod/src/v4/classic/tests/string.test.ts", "packages/zod/src/v4/classic/tests/to-json-schema.test.ts"], "given_files": ["packages/zod/src/v4/core/schemas.ts"]}, "id": "9a447802c07b2c5ef9aed13c", "metadata": {"changed_files": ["packages/zod/src/v4/classic/tests/string.test.ts", "packages/zod/src/v4/classic/tests/to-json-schema.test.ts", "packages/zod/src/v4/core/json-schema-processors.ts", "packages/zod/src/v4/core/schemas.ts"], "created_at": "2026-08-31T19:06:53Z", "fix_commit": "07c43e2a08f67082bd35c158d528d571a36094e0", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 10, "deletions": 2, "is_test": false, "path": "packages/zod/src/v4/core/json-schema-processors.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 12, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/classic/tests/string.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 15, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/classic/tests/to-json-schema.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"packages/zod/src/v4/classic/tests/string.test.ts": ["packages", "string", "zod"], "packages/zod/src/v4/classic/tests/to-json-schema.test.ts": ["json", "packages", "schema", "zod"], "packages/zod/src/v4/core/json-schema-processors.ts": ["json", "packages", "schema", "zod"]}}, "merged_at": "2026-08-31T20:01:18Z", "pr": 6534, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/colinhacks/zod/pull/6534"}, "query": {"anchor_diff": "@@ -1028,10 +1028,13 @@ export interface $ZodBase64 extends $ZodType {\n _zod: $ZodBase64Internals;\n }\n \n+// lax on purpose: the quantified regexes.base64 overflows the regex stack on multi-MB input and its leading ^$| alternation leaks through template-literal composition; isValidBase64 enforces length and padding\n+export const base64Charset: RegExp = /^[0-9a-zA-Z+/]*={0,2}$/;\n+\n export const $ZodBase64: core.$constructor<$ZodBase64> = /*@__PURE__*/ core.$constructor(\n \"$ZodBase64\",\n (inst, def): void => {\n- def.pattern ??= regexes.base64;\n+ def.pattern ??= base64Charset;\n $ZodStringFormat.init(inst, def);\n \n inst._zod.bag.contentEncoding = \"base64\";\n@@ -1051,8 +1054,8 @@ export const $ZodBase64: core.$constructor<$ZodBase64> = /*@__PURE__*/ core.$con\n );\n \n ////////////////////////////// ZodBase64URL //////////////////////////////\n-// charset only — the quantified regexes.base64url overflows the regex stack on multi-MB input; isValidBase64 enforces length on the padded string\n-const base64urlCharset = /^[A-Za-z0-9_-]*$/;\n+// lax on purpose: the quantified regexes.base64url overflows the regex stack on multi-MB input; isValidBase64 enforces length on the padded string\n+export const base64urlCharset: RegExp = /^[A-Za-z0-9_-]*$/;\n \n export function isValidBase64URL(data: string): boolean {\n if (!base64urlCharset.test(data)) return false;\n@@ -1071,7 +1074,7 @@ export interface $ZodBase64URL extends $ZodType {\n export const $ZodBase64URL: core.$constructor<$ZodBase64URL> = /*@__PURE__*/ core.$constructor(\n \"$ZodBase64URL\",\n (inst, def): void => {\n- def.pattern ??= regexes.base64url;\n+ def.pattern ??= base64urlCharset;\n $ZodStringFormat.init(inst, def);\n \n inst._zod.bag.contentEncoding = \"base64url\";", "anchor_file": "packages/zod/src/v4/core/schemas.ts", "intent": "Keep the runtime base64 regexes linear so composed parse paths cannot overflow\n\nFixes the finding from the #6528 review: `z.templateLiteral([\"id-\", z.base64url()]).safeParse` threw `RangeError: Maximum call stack size exceeded` on multi-megabyte input. The quantified block forms (`(?:[...]{4})*`) recurse per block in V8's regex engine, so ~8M chars overflows the stack. `z.base64()` and `z.base64url()` were already mitigated internally, but template literals compose member `def.pattern`s and test them on every parse.\n\nThe split, reworked per review: the public `z.regexes.base64` and `z.regexes.base64url` keep their strict shipped semantics and are untouched. The lax linear forms (`/^[0-9a-zA-Z+/]*={0,2}$/`, `/^[A-Za-z0-9_-]*$/`) live module-local in `schemas.ts` and become `def.pattern` for the two formats — parse validation is unchanged because `isValidBase64`/`isValidBase64URL` enforce the length rules. The JSON Schema emitter swaps the lax patterns back to the strict exports by reference, at both consumer sites: `stringProcessor`'s `pattern`/`allOf` and `recordProcessor`'s `patternProperties` (the review caught that `z.looseRecord(z.base64url(), …)` would otherwise emit the lax key — now pinned by a test). `toJSONSchema(z.base64url())` still emits the length-aware pattern from #6527; its snapshot and agreement tests pass unchanged, and `base64` gains the symmetric agreement test. `templateLiteralProcessor` is deliberately left lax: its emitted pattern then agrees with the (length-lax) composed parse.\n\nThis also fixes a second bug the overflow investigation surfaced: `regexes.base64`'s leading `^$|` alternation leaked through template-literal composition, so on `main` `z.templateLiteral([\"id-\", z.base64()])` accepts `\"AAAA\"` with the prefix dropped and rejects the vali\n...[truncated]"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "74f9a6d3f2818f24e6df5394b8b6e60acb176463", "candidate_corpus": {"base_commit": "74f9a6d3f2818f24e6df5394b8b6e60acb176463", "type": "repo_at_base_commit"}, "gold": {"files": ["packages/zod/src/v4/classic/tests/assignability.test.ts"], "given_files": ["packages/zod/src/v4/core/util.ts"]}, "id": "e94550baa0c88de994d157f9", "metadata": {"changed_files": ["packages/zod/src/v4/classic/tests/assignability.test.ts", "packages/zod/src/v4/core/util.ts"], "created_at": "2026-08-31T18:21:29Z", "fix_commit": "2ec972ecc5a8af8135ed072d2d5b5363c27bb46f", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 3, "deletions": 0, "is_test": true, "path": "packages/zod/src/v4/classic/tests/assignability.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"packages/zod/src/v4/classic/tests/assignability.test.ts": ["packages", "zod"]}}, "merged_at": "2026-08-31T19:07:26Z", "pr": 6533, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/colinhacks/zod/pull/6533"}, "query": {"anchor_diff": "@@ -98,15 +98,15 @@ type ToZodKeyMismatch = schemas.$ZodType & {\n \"types do not match\": { expected: Expected; received: Received };\n };\n \n-// An enum reference and the union of exactly its members are mutually assignable but not identical, so `AssertEqual` alone rejects `z.enum(SomeEnum)` against a `SomeEnum` target. Rebuilding the string/number part of each side through a mapped type collapses that one difference and nothing else — plain literals agains\n-type ToZodNormalizeEnum = { [K in Extract]: K }[Extract] | Exclude;\n+// An enum reference and the union of exactly its members are mutually assignable but not identical, so `AssertEqual` alone rejects `z.enum(SomeEnum)` against a `SomeEnum` target. Unioning each side with a private dummy forces the union to be rebuilt, which collapses that one difference and nothing else — plain litera\n+declare const toZodDummy: unique symbol;\n \n-// Recurses only through types identical to their own homomorphic rebuild, which preserves the exactness guarantees: an intersection, a call signature and `readonly`/optional modifiers all survive or block the walk, so only enum leaves are normalized.\n+// Recurses only through types identical to their own homomorphic rebuild, which preserves the exactness guarantees: an intersection, a call signature and `readonly`/optional modifiers all survive or block the walk, so only leaves are normalized.\n type ToZodNormalize = [T] extends [object]\n ? AssertEqual extends true\n ? { [K in keyof T]: ToZodNormalize }\n : T\n- : ToZodNormalizeEnum;\n+ : T | typeof toZodDummy;\n \n type ToZodEqual = AssertEqual extends true\n ? true", "anchor_file": "packages/zod/src/v4/core/util.ts", "intent": "Collapse toZod's enum leaf normalizer to a dummy union\n\nFollow-up to #6528, from the request to find a smaller formulation than the mapped-key normalizer.\n\nThe enum-leaf machinery reduces to a single union. `{ [K in Extract]: K }[Extract] | Exclude` becomes `T | typeof toZodDummy`, where `toZodDummy` is a private, unexported `unique symbol`. Unioning either side with anything forces TypeScript to rebuild the union, and the rebuilt unions compare identical — `E | D` and `E.A | E.B | D` are the same type, while everything else the exactness check distinguishes stays distinguished. No index-signature lookup, no `Extract`/`Exclude` split. The recursive walk with its flat-rebuild guard stays: it is what keeps intersections, call signatures, classes with private members, and `readonly`/optional modifiers strict, and no leaf-level trick can reach a nested enum without it.\n\nVerified differentially: both implementations were run side by side over 35 probes — every fixed case (flat, nested, arrays, tuples, records, nullable, optional), every guarantee (`any`, `unknown`, brands, subsets, plain string literals vs a nominal enum, plain numeric literals vs a numeric enum, intersection-vs-flat, `readonly`, class instances with private members, enums nested in generics and function signatures) — with identical results on TypeScript 5.5, 6, and 7.0.2. The probe files live in the triage directory for #6524. The test suite gains one negative control: plain `1 | 2` does not satisfy a numeric enum target, which is the distinction the union rebuild had to preserve and the one place the two enum flavors differ (numeric enums are mutually *assignable* with their literals; identity still separates them).\n\nType-only change; zero runtime, memory, and bund\n...[truncated]"}, "repo": "colinhacks/zod", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "b0d28c42987c0c8a4e3c99cdbbbb57450e06dfda", "candidate_corpus": {"base_commit": "b0d28c42987c0c8a4e3c99cdbbbb57450e06dfda", "type": "repo_at_base_commit"}, "gold": {"files": ["src/router/reg-exp-router/trie.ts", "src/utils/url.test.ts", "src/router/common.case.test.ts"], "given_files": ["src/utils/url.ts"]}, "id": "ee59d1fa6f0ba4572e2cd741", "metadata": {"changed_files": ["src/router/common.case.test.ts", "src/router/reg-exp-router/trie.ts", "src/utils/url.test.ts", "src/utils/url.ts"], "created_at": "2026-10-12T02:04:52Z", "fix_commit": "1d029dcedd4b8cd7eaed718efe5dfa2f5bab9b30", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "src/router/reg-exp-router/trie.ts", "signals": ["shared_changed_symbol"]}, {"additions": 10, "deletions": 0, "is_test": true, "path": "src/utils/url.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 9, "deletions": 0, "is_test": true, "path": "src/router/common.case.test.ts", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"src/router/common.case.test.ts": ["case", "router"], "src/router/reg-exp-router/trie.ts": ["router"], "src/utils/url.test.ts": ["url"]}}, "merged_at": "2026-10-16T09:56:35Z", "pr": 5552, "ripple_relation": ["shared_changed_symbol", "path_token_overlap", "optional_test_ripple"], "source_pr": "https://github.com/honojs/hono/pull/5552"}, "query": {"anchor_diff": "@@ -23,7 +23,7 @@ export const splitRoutingPath = (routePath: string): string[] => {\n const extractGroupsFromPath = (path: string): { groups: [string, string][]; path: string } => {\n const groups: [string, string][] = []\n \n- path = path.replace(/\\{[^}]+\\}/g, (match, index) => {\n+ path = path.replace(/\\{(?:\\{[\\d,]+\\}|[^}])+\\}/g, (match, index) => {\n const mark = `@${index}`\n groups.push([mark, match])\n return mark", "anchor_file": "src/utils/url.ts", "intent": "fix(router): handle slashes after regex quantifiers\n\nRoute patterns such as `/x/:prefix{a{2}/b}/x` should match `/x/aa/b/x`, capturing `aa/b` as `prefix`.\n\nCurrently, pattern masking stops at the quantifier’s closing `}`, leaving the following `/` exposed to path splitting.\n\nThis is a fairly rare edge case, so I hesitated over whether it was worth adding code to support it. However, the routing syntax allows this pattern, so I’m opening this PR.\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code\n\nfix(router): preserve regex quantifiers when splitting route paths"}, "repo": "honojs/hono", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "b0d28c42987c0c8a4e3c99cdbbbb57450e06dfda", "candidate_corpus": {"base_commit": "b0d28c42987c0c8a4e3c99cdbbbb57450e06dfda", "type": "repo_at_base_commit"}, "gold": {"files": ["src/utils/url.ts", "src/router/common.case.test.ts"], "given_files": ["src/router/reg-exp-router/trie.ts"]}, "id": "ff7527331b8f25f286b95e1d", "metadata": {"changed_files": ["src/router/common.case.test.ts", "src/router/reg-exp-router/trie.ts", "src/utils/url.test.ts", "src/utils/url.ts"], "created_at": "2026-10-12T02:04:52Z", "fix_commit": "1d029dcedd4b8cd7eaed718efe5dfa2f5bab9b30", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "src/utils/url.ts", "signals": ["shared_changed_symbol"]}, {"additions": 9, "deletions": 0, "is_test": true, "path": "src/router/common.case.test.ts", "signals": ["path_token_overlap", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"src/router/common.case.test.ts": ["case", "router"]}}, "merged_at": "2026-10-16T09:56:35Z", "pr": 5552, "ripple_relation": ["shared_changed_symbol", "path_token_overlap", "optional_test_ripple"], "source_pr": "https://github.com/honojs/hono/pull/5552"}, "query": {"anchor_diff": "@@ -24,7 +24,7 @@ export class Trie {\n let markedPath = path\n for (let i = 0; ;) {\n let replaced = false\n- markedPath = markedPath.replace(/\\{[^}]+\\}/g, (m) => {\n+ markedPath = markedPath.replace(/\\{(?:\\{[\\d,]+\\}|[^}])+\\}/g, (m) => {\n const mark = `@\\\\${i}`\n groups[i] = [mark, m]\n i++", "anchor_file": "src/router/reg-exp-router/trie.ts", "intent": "fix(router): handle slashes after regex quantifiers\n\nRoute patterns such as `/x/:prefix{a{2}/b}/x` should match `/x/aa/b/x`, capturing `aa/b` as `prefix`.\n\nCurrently, pattern masking stops at the quantifier’s closing `}`, leaving the following `/` exposed to path splitting.\n\nThis is a fairly rare edge case, so I hesitated over whether it was worth adding code to support it. However, the routing syntax allows this pattern, so I’m opening this PR.\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code\n\nfix(router): preserve regex quantifiers when splitting route paths"}, "repo": "honojs/hono", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "cc92a59f60caf7fe4f61cd01d0d6afb66426c6ae", "candidate_corpus": {"base_commit": "cc92a59f60caf7fe4f61cd01d0d6afb66426c6ae", "type": "repo_at_base_commit"}, "gold": {"files": ["src/request.test.ts", "runtime-tests/bun/index.test.tsx"], "given_files": ["src/request.ts"]}, "id": "07471e1a5add0b7a5a28b623", "metadata": {"changed_files": ["runtime-tests/bun/index.test.tsx", "src/request.test.ts", "src/request.ts"], "created_at": "2026-10-07T06:38:55Z", "fix_commit": "5c292393f21e1693b54a6081491e4e83215d02ea", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 82, "deletions": 18, "is_test": true, "path": "src/request.test.ts", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 14, "deletions": 0, "is_test": true, "path": "runtime-tests/bun/index.test.tsx", "signals": ["gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"runtime-tests/bun/index.test.tsx": ["bun"], "src/request.test.ts": ["request"]}}, "merged_at": "2026-10-09T03:53:07Z", "pr": 5536, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/honojs/hono/pull/5536"}, "query": {"anchor_diff": "@@ -214,9 +214,16 @@ export class HonoRequest

{\n return parseBody(this, options)\n }\n \n- #cachedBody = (key: keyof Body) => {\n+ #cachedBody = >(key: K): Promise => {\n const { bodyCache, raw } = this\n- if (key === 'json' || key === 'text') {\n+ const cached = bodyCache[key]\n+ if (cached) {\n+ return cached as unknown as Promise\n+ }\n+ // Read before consuming the body: Bun generates the multipart boundary lazily,\n+ // and a header read afterwards would not match the serialized bytes\n+ const contentType = raw.headers.get('content-type')\n+ if (key === 'text') {\n const text = (bodyCache.text ??= (\n bodyCache.arrayBuffer\n ? (bodyCache.arrayBuffer as unknown as Promise).then((buffer) =>\n@@ -224,7 +231,7 @@ export class HonoRequest

{\n )\n : raw.text()\n ) as never) as unknown as Promise\n- return key === 'text' ? text : (bodyCache.json ??= text.then((text) => JSON.parse(text)))\n+ return text as Promise\n }\n const bytes = (bodyCache.arrayBuffer ??= (\n bodyCache.text\n@@ -234,14 +241,14 @@ export class HonoRequest

{\n : raw.arrayBuffer()\n ) as never) as unknown as Promise\n if (key === 'arrayBuffer') {\n- return bytes\n+ return bytes as Promise\n }\n return (bodyCache[key] ??= bytes.then(\n (buffer) =>\n new Response(buffer, {\n- headers: { 'Content-Type': raw.headers.get('content-type') ?? '' },\n+ headers: contentType ? { 'Content-Type': contentType } : undefined,\n })[key]() as never\n- ) as never)\n+ ) as never) as unknown as Promise\n }\n \n /**\n@@ -257,7 +264,7 @@ export class HonoRequest

{\n * ```\n */\n json(): Promise {\n- return this.#cachedBody('json')\n+ return this.#cachedBody('text').then((text) => JSON.parse(text))\n }\n \n /**\n@@ -440,11 +447,10 @@ export const cloneRawRequest = async (req: HonoRequest): Promise => {\n })\n }\n \n- const rebuiltFromText = !req.bodyCache.arrayBuffer\n- const body: BodyInit = await req.arrayBuffer()\n+ const body = await req.arrayBuffer()\n const headers = req.header()\n- if (rebuiltFromText) {\n- // Re-encoded text may differ in length from the original bytes (e.g. a BOM)\n+ if (Number(headers['content-length']) !== body.byteLength) {\n+ // Re-encoded text may differ in length from the original bytes (e.g. a BOM or invalid UTF-8)\n delete headers['content-length']\n }", "anchor_file": "src/request.ts", "intent": "preserve body cache behavior across runtimes\n\n### Validate Content-Length: c169ae46\n\nRe-encoding cached text can change the body’s byte length, leaving the original Content-Length stale and causing forwarded requests to fail. This fix prevents stale length headers from being reused after `arrayBuffer()` reads or repeated cloning.\n\n### Return independent JSON objects: ddb5c128\n\nSharing the parsed object would carry mutations into subsequent calls, so this change preserves the previous behavior of returning independent objects. Since `json()` is typically called only once per request, parsing the cached text on each call is expected to have little performance impact.\n\n### Read Content-Type before consuming the body: c97181a6\n\nOn Bun, the following command fails with a `500` response before this commit. Reading Content-Type before consuming the body preserves the matching multipart boundary and makes it return `200 b`.\n\n```sh\nbun -e \"const { Hono } = await import('./src/index'); const app = new Hono(); app.onError((e, c) => c.text(e.message, 500)); app.post('/', async (c) => c.text(String((await c.req.formData()).get('a')))); const fd = new FormData(); fd.append('a', 'b'); const res = await app.request('/', { method: 'POST', body: fd }); console.log(res.status, await res.text())\"\n```\n\n### Return cached representations first: f7d4c67c\n\nReading an externally cached body representation could trigger an unhandled rejection after the raw body had already been consumed.\n\nfix(request): validate content length when cloning cached bodies\n\nfix(request): return independent JSON objects from cached text\n\nfix(request): read the media type before consuming the body\n\nfix(request): return the cached representation before deriving the body"}, "repo": "honojs/hono", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "371b2877e3a5869e13f808fbc4778603978b7127", "candidate_corpus": {"base_commit": "371b2877e3a5869e13f808fbc4778603978b7127", "type": "repo_at_base_commit"}, "gold": {"files": ["src/context.test.ts"], "given_files": ["src/context.ts"]}, "id": "35553ab58dbb622f3be9f32d", "metadata": {"changed_files": ["docs/MIGRATION.md", "src/context.test.ts", "src/context.ts"], "created_at": "2026-10-06T12:24:36Z", "fix_commit": "2772c28f7a8304edec67a9eface937841cee1f74", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 8, "deletions": 0, "is_test": true, "path": "src/context.test.ts", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"src/context.test.ts": ["context"]}}, "merged_at": "2026-10-06T12:26:57Z", "pr": 5534, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/honojs/hono/pull/5534"}, "query": {"anchor_diff": "@@ -749,8 +749,12 @@ export class Context<\n arg?: U | ResponseOrInit,\n headers?: HeaderRecord\n ): JSONRespondReturn => {\n+ const body = JSON.stringify(object)\n+ if (body === undefined) {\n+ throw new TypeError('Value is not JSON serializable')\n+ }\n return this.#newResponse(\n- JSON.stringify(object),\n+ body,\n arg,\n setDefaultContentType('application/json', headers)\n ) /* eslint-disable @typescript-eslint/no-explicit-any */ as any", "anchor_file": "src/context.ts", "intent": "feat(context)!: throw on a value that is not JSON serializable in `c.json()`\n\nFixes #2343\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code\n\nfeat(context)!: throw on a value that is not JSON serializable in `c.json()`"}, "repo": "honojs/hono", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "52944f0642fa0f210711159c549fcd2a96d306f3", "candidate_corpus": {"base_commit": "52944f0642fa0f210711159c549fcd2a96d306f3", "type": "repo_at_base_commit"}, "gold": {"files": ["src/request.test.ts"], "given_files": ["src/request.ts"]}, "id": "2b4d00faab4016ff85e30118", "metadata": {"changed_files": ["docs/MIGRATION.md", "src/request.test.ts", "src/request.ts"], "created_at": "2026-10-06T12:14:38Z", "fix_commit": "371b2877e3a5869e13f808fbc4778603978b7127", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 10, "deletions": 0, "is_test": true, "path": "src/request.test.ts", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"src/request.test.ts": ["request"]}}, "merged_at": "2026-10-06T12:16:52Z", "pr": 5533, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/honojs/hono/pull/5533"}, "query": {"anchor_diff": "@@ -255,7 +255,7 @@ export class HonoRequest

{\n * })\n * ```\n */\n- json(): Promise {\n+ json(): Promise {\n return this.#cachedBody('text').then((text: string) => JSON.parse(text))\n }", "anchor_file": "src/request.ts", "intent": "feat(request)!: `json()` returns unknown\n\nResolves https://github.com/orgs/honojs/discussions/4979\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code\n\nfeat(request)!: `json()` returns unknown"}, "repo": "honojs/hono", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "2fa7732e1b1b4b81c43a643be2cf22f0947a8d9a", "candidate_corpus": {"base_commit": "2fa7732e1b1b4b81c43a643be2cf22f0947a8d9a", "type": "repo_at_base_commit"}, "gold": {"files": ["src/request.test.ts"], "given_files": ["src/request.ts"]}, "id": "f4c358d5cc6971fb6dbd5929", "metadata": {"changed_files": ["docs/MIGRATION.md", "src/hono.test.ts", "src/request.test.ts", "src/request.ts", "src/validator/validator.ts"], "created_at": "2026-10-06T12:07:15Z", "fix_commit": "52944f0642fa0f210711159c549fcd2a96d306f3", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 9, "deletions": 0, "is_test": true, "path": "src/request.test.ts", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"src/request.test.ts": ["request"]}}, "merged_at": "2026-10-06T12:09:40Z", "pr": 5532, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/honojs/hono/pull/5532"}, "query": {"anchor_diff": "@@ -143,8 +143,8 @@ export class HonoRequest

{\n * ```\n */\n query(key: string): string | undefined\n- query(): Record\n- query(key?: string) {\n+ query(): Record\n+ query(key?: string): string | undefined | Record {\n return getQueryParam(this.url, key)\n }\n \n@@ -162,8 +162,8 @@ export class HonoRequest

{\n * ```\n */\n queries(key: string): string[] | undefined\n- queries(): Record\n- queries(key?: string) {\n+ queries(): Record\n+ queries(key?: string): string[] | undefined | Record {\n return getQueryParams(this.url, key)\n }", "anchor_file": "src/request.ts", "intent": "feat(request)!: `query()` and `queries()` may return `undefined`\n\nFixes https://github.com/honojs/hono/issues/3426\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code\n\nfeat(request)!: `query()` and `queries()` may return `undefined`"}, "repo": "honojs/hono", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "e92826579e5da60671a01d73f0ad2bf32a834be8", "candidate_corpus": {"base_commit": "e92826579e5da60671a01d73f0ad2bf32a834be8", "type": "repo_at_base_commit"}, "gold": {"files": ["src/helper/factory/index.ts"], "given_files": ["src/validator/validator.ts"]}, "id": "2566783061becb60447c8912", "metadata": {"changed_files": ["src/helper/factory/define-handler.test.ts", "src/helper/factory/define-handler.ts", "src/helper/factory/index.ts", "src/validator/validator.ts"], "created_at": "2026-10-06T11:24:48Z", "fix_commit": "683ea769aeabbbc55fb828ecec8778f082bfe288", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 37, "deletions": 2, "is_test": false, "path": "src/helper/factory/index.ts", "signals": ["shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"src/helper/factory/index.ts": ["factory"]}}, "merged_at": "2026-10-08T04:45:50Z", "pr": 5531, "ripple_relation": ["shared_changed_symbol"], "source_pr": "https://github.com/honojs/hono/pull/5531"}, "query": {"anchor_diff": "@@ -43,6 +43,80 @@ export type ExtractValidationResponse = VF extends (value: any, c: any) => i\n : never // anything else → never\n : never // Can't extract → never\n \n+/**\n+ * Get the value of the validation target from the request.\n+ * Returns a Promise only for `json` and `form`.\n+ */\n+export const getValidationTarget = (\n+ c: Context,\n+ target: keyof ValidationTargets\n+): unknown | Promise => {\n+ const contentType = c.req.header('Content-Type')\n+\n+ switch (target) {\n+ case 'json':\n+ if (!contentType || !jsonRegex.test(contentType)) {\n+ return {}\n+ }\n+ return c.req.json().catch(() => {\n+ throw new HTTPException(400, { message: 'Malformed JSON in request body' })\n+ })\n+ case 'form': {\n+ if (\n+ !contentType ||\n+ !(multipartRegex.test(contentType) || urlencodedRegex.test(contentType))\n+ ) {\n+ return {}\n+ }\n+ return getForm(c, contentType)\n+ }\n+ case 'query':\n+ return Object.fromEntries(\n+ Object.entries(c.req.queries()).map(([k, v]) => {\n+ return v?.length === 1 ? [k, v[0]] : [k, v]\n+ })\n+ )\n+ case 'param':\n+ return c.req.param() as Record\n+ case 'header':\n+ return c.req.header()\n+ case 'cookie':\n+ return getCookie(c)\n+ }\n+}\n+\n+const getForm = async (c: Context, contentType: string): Promise> => {\n+ let formData: FormData\n+\n+ if (c.req.bodyCache.formData) {\n+ formData = await c.req.bodyCache.formData\n+ } else {\n+ try {\n+ const arrayBuffer = await c.req.arrayBuffer()\n+ formData = await bufferToFormData(arrayBuffer, contentType)\n+ c.req.bodyCache.formData = formData\n+ } catch (e) {\n+ let message = 'Malformed FormData request.'\n+ message += e instanceof Error ? ` ${e.message}` : ` ${String(e)}`\n+ throw new HTTPException(400, { message })\n+ }\n+ }\n+\n+ const form: BodyData<{ all: true }> = Object.create(null)\n+ formData.forEach((value, key) => {\n+ if (key.endsWith('[]')) {\n+ ;((form[key] ??= []) as unknown[]).push(value)\n+ } else if (Array.isArray(form[key])) {\n+ ;(form[key] as unknown[]).push(value)\n+ } else if (Object.hasOwn(form, key)) {\n+ form[key] = [form[key] as string | File, value]\n+ } else {\n+ form[key] = value\n+ }\n+ })\n+ return form\n+}\n+\n export const validator = <\n InputType,\n P extends string,\n@@ -87,77 +161,7 @@ export const validator = <\n validationFunc: VF\n ): MiddlewareHandler> => {\n return async (c, next) => {\n- let value = {}\n- const contentType = c.req.header('Content-Type')\n-\n- switch (target) {\n- case 'json':\n- if (!contentType || !jsonRegex.test(contentType)) {\n- break\n- }\n- try {\n- value = await c.req.json()\n- } catch {\n- const message = 'Malformed JSON in request body'\n- throw new HTTPException(400, { message })\n- }\n- break\n- case 'form': {\n- if (\n- !contentType ||\n- !(multipartRegex.test(contentType) || urlencodedRegex.test(contentType))\n- ) {\n- break\n- }\n-\n- let formData: FormData\n-\n- if (c.req.bodyCache.formData) {\n- formData = await c.req.bodyCache.formData\n- } else {\n- try {\n- const arrayBuffer = await c.req.arrayBuffer()\n- formData = await bufferToFormData(arrayBuffer, contentType)\n- c.req.bodyCache.formData = formData\n- } catch (e) {\n- let message = 'Malformed FormData request.'\n- message += e instanceof Error ? ` ${e.message}` : ` ${String(e)}`\n- throw new HTTPException(400, { message })\n- }\n- }\n-\n- const form: BodyData<{ all: true }> = Object.create(null)\n- formData.forEach((value, key) => {\n- if (key.endsWith('[]')) {\n- ;((form[key] ??= []) as unknown[]).push(value)\n- } else if (Array.isArray(form[key])) {\n- ;(form[key] as unknown[]).push(value)\n- } else if (Object.hasOwn(form, key)) {\n- form[key] = [form[key] as string | File, value]\n- } else {\n- form[key] = value\n- }\n- })\n- value = form\n- break\n- }\n- case 'query':\n- value = Object.fromEntries(\n- Object.entries(c.req.queries()).map(([k, v]) => {\n- return v?.length === 1 ? [k, v[0]] : [k, v]\n- })\n- )\n- break\n- case 'param':\n- value = c.req.param() as Record\n- break\n- case 'header':\n- value = c.req.header()\n- break\n- case 'cookie':\n- value = getCookie(c)\n- break\n- }\n+ const value = await getValidationTarget(c, target)\n \n const res = await validationFunc(value as never, c as never)", "anchor_file": "src/validator/validator.ts", "intent": "feat(factory): add experimental `defineHandler()`\n\n## The new API:\n\n```ts\nimport { Hono } from 'hono'\nimport { defineHandler } from 'hono/factory'\nimport * as v from 'valibot'\n\nconst app = new Hono()\n\nconst schema = v.object({\n page: v.optional(v.string(), '1')\n})\n\nconst handler = defineHandler({ query: schema })((c, { query }) => {\n return

you are page {query.page}

\n})\n\napp.get('/', handler)\n\nexport default app\n```\n\n---\n\nThis PR adds `validatedHandler()` to `hono/validator` as an experimental API. It defines a handler with request and response validation in one place.\n\n```ts\nimport { validatedHandler } from 'hono/validator'\nimport * as v from 'valibot'\n\nconst UserSchema = v.object({ name: v.string(), age: v.number() })\nconst ResponseSchme = v.object({ ok: v.boolean() })\n\nconst handler = validatedHandler({\n json: UserSchema,\n response: ResponseSchme,\n handle: async (c) => {\n const { name, age } = c.req.valid('json')\n c.status(201)\n return { ok: true }\n }\n})\n\napp.post('/users/:id', handler)\n```\n\nFeatures:\n\n- `param`, `query`, `header`, `cookie`, `form`, and `json` are validated with the existing `validator()`. The values are available via `c.req.valid()`.\n- A value returned from `handle` is validated with response and returned as JSON. The status comes from `c.status()`. A Response returned from `handle` is returned as is.\n- Each validation accepts a Standard Schema or a validation function. No dependencies are added.\n- When a validation fails, an `HTTPException` is thrown: 400 for the request and 500 for the response. Its res is the default JSON response, and its cause is `{ target, issues }`, so `onError` can customize it. The default JSON does not include the input value.\n- The schemas are available as `handler.validations`, so tools such as an\n...[truncated]"}, "repo": "honojs/hono", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "e92826579e5da60671a01d73f0ad2bf32a834be8", "candidate_corpus": {"base_commit": "e92826579e5da60671a01d73f0ad2bf32a834be8", "type": "repo_at_base_commit"}, "gold": {"files": ["src/validator/validator.ts"], "given_files": ["src/helper/factory/index.ts"]}, "id": "b99e72f637ae8821468c08df", "metadata": {"changed_files": ["src/helper/factory/define-handler.test.ts", "src/helper/factory/define-handler.ts", "src/helper/factory/index.ts", "src/validator/validator.ts"], "created_at": "2026-10-06T11:24:48Z", "fix_commit": "683ea769aeabbbc55fb828ecec8778f082bfe288", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 75, "deletions": 71, "is_test": false, "path": "src/validator/validator.ts", "signals": ["shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_stem_hint"], "nonfatal_hits": {"src/validator/validator.ts": ["validator"]}}, "merged_at": "2026-10-08T04:45:50Z", "pr": 5531, "ripple_relation": ["shared_changed_symbol"], "source_pr": "https://github.com/honojs/hono/pull/5531"}, "query": {"anchor_diff": "@@ -14,6 +14,11 @@ import type {\n IntersectNonAnyTypes,\n MiddlewareHandler,\n } from '../../types'\n+import { defineHandler } from './define-handler'\n+import type { DefineHandler } from './define-handler'\n+\n+export { defineHandler }\n+export type { StandardSchema, ValidationIssue, ValidationFailure } from './define-handler'\n \n type InitApp = (app: Hono) => void\n \n@@ -350,10 +355,22 @@ export class Factory {\n return app\n }\n \n- createMiddleware = | void = void>(\n+ defineMiddleware = | void = void>(\n middleware: MiddlewareHandler\n ): MiddlewareHandler => middleware\n \n+ defineHandler: DefineHandler = defineHandler\n+\n+ /**\n+ * @deprecated Use `defineMiddleware()` instead. It will be removed in the next major version.\n+ */\n+ createMiddleware = this.defineMiddleware\n+\n+ /**\n+ * @deprecated Use `defineHandler()` instead. It will be removed in the next major version.\n+ * Pass the middleware before the handler:\n+ * `defineHandler(auth, (c) => ...)`.\n+ */\n createHandlers: CreateHandlersInterface = (...handlers: any) => {\n // @ts-expect-error this should not be typed\n return handlers.filter((handler) => handler !== undefined)\n@@ -365,7 +382,20 @@ export const createFactory = (in\n defaultAppOptions?: HonoOptions\n }): Factory => new Factory(init)\n \n-export const createMiddleware = <\n+/**\n+ * `defineMiddleware()` defines a middleware with the types.\n+ *\n+ * @see {@link https://hono.dev/docs/helpers/factory#definemiddleware}\n+ *\n+ * @example\n+ * ```ts\n+ * const auth = defineMiddleware<{ Variables: { user: User } }>(async (c, next) => {\n+ * c.set('user', await getUser(c))\n+ * await next()\n+ * })\n+ * ```\n+ */\n+export const defineMiddleware = <\n E extends Env = any,\n P extends string = string,\n I extends Input = {},\n@@ -373,3 +403,8 @@ export const createMiddleware = <\n >(\n middleware: MiddlewareHandler\n ): MiddlewareHandler => middleware\n+\n+/**\n+ * @deprecated Use `defineMiddleware()` instead. It will be removed in the next major version.\n+ */\n+export const createMiddleware = defineMiddleware", "anchor_file": "src/helper/factory/index.ts", "intent": "feat(factory): add experimental `defineHandler()`\n\n## The new API:\n\n```ts\nimport { Hono } from 'hono'\nimport { defineHandler } from 'hono/factory'\nimport * as v from 'valibot'\n\nconst app = new Hono()\n\nconst schema = v.object({\n page: v.optional(v.string(), '1')\n})\n\nconst handler = defineHandler({ query: schema })((c, { query }) => {\n return

you are page {query.page}

\n})\n\napp.get('/', handler)\n\nexport default app\n```\n\n---\n\nThis PR adds `validatedHandler()` to `hono/validator` as an experimental API. It defines a handler with request and response validation in one place.\n\n```ts\nimport { validatedHandler } from 'hono/validator'\nimport * as v from 'valibot'\n\nconst UserSchema = v.object({ name: v.string(), age: v.number() })\nconst ResponseSchme = v.object({ ok: v.boolean() })\n\nconst handler = validatedHandler({\n json: UserSchema,\n response: ResponseSchme,\n handle: async (c) => {\n const { name, age } = c.req.valid('json')\n c.status(201)\n return { ok: true }\n }\n})\n\napp.post('/users/:id', handler)\n```\n\nFeatures:\n\n- `param`, `query`, `header`, `cookie`, `form`, and `json` are validated with the existing `validator()`. The values are available via `c.req.valid()`.\n- A value returned from `handle` is validated with response and returned as JSON. The status comes from `c.status()`. A Response returned from `handle` is returned as is.\n- Each validation accepts a Standard Schema or a validation function. No dependencies are added.\n- When a validation fails, an `HTTPException` is thrown: 400 for the request and 500 for the response. Its res is the default JSON response, and its cause is `{ target, issues }`, so `onError` can customize it. The default JSON does not include the input value.\n- The schemas are available as `handler.validations`, so tools such as an\n...[truncated]"}, "repo": "honojs/hono", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "08a023cbfde55b434fb0fb30fae35d42e4bf20aa", "candidate_corpus": {"base_commit": "08a023cbfde55b434fb0fb30fae35d42e4bf20aa", "type": "repo_at_base_commit"}, "gold": {"files": ["src/middleware/serve-static/index.test.ts"], "given_files": ["src/middleware/serve-static/index.ts"]}, "id": "4808655d254e1c60a0357de2", "metadata": {"changed_files": ["src/middleware/serve-static/index.test.ts", "src/middleware/serve-static/index.ts"], "created_at": "2026-10-04T13:16:03Z", "fix_commit": "588ec13fa68ea44fed1b5e1b503341db2bf09d70", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 52, "deletions": 0, "is_test": true, "path": "src/middleware/serve-static/index.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"src/middleware/serve-static/index.test.ts": ["middleware", "serve", "static"]}}, "merged_at": "2026-10-13T08:18:10Z", "pr": 5514, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/honojs/hono/pull/5514"}, "query": {"anchor_diff": "@@ -59,6 +59,10 @@ export const serveStatic = (\n return next()\n }\n \n+ if (c.req.method !== 'GET' && c.req.method !== 'HEAD') {\n+ return next()\n+ }\n+\n let filename: string\n \n if (options.path) {", "anchor_file": "src/middleware/serve-static/index.ts", "intent": "fix(serve-static): only serve GET and HEAD requests\n\n#5223\n\nCall `next()` for requests other than GET and HEAD.\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code\n\nfix(serve-static): only serve GET and HEAD requests"}, "repo": "honojs/hono", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "c9b1148b5b8799758756cbec7c0d1ac187d37f1a", "candidate_corpus": {"base_commit": "c9b1148b5b8799758756cbec7c0d1ac187d37f1a", "type": "repo_at_base_commit"}, "gold": {"files": ["src/black/linegen.py"], "given_files": ["src/black/nodes.py"]}, "id": "03a4771344ea91438a5e0b58", "metadata": {"changed_files": ["CHANGES.md", "src/black/linegen.py", "src/black/nodes.py", "tests/data/cases/preview_type_param_defaults_string_split.py"], "created_at": "2026-10-09T17:07:54Z", "fix_commit": "c45f21d0399747189eedcc6c9a1614b3cf49dc0f", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 0, "deletions": 12, "is_test": false, "path": "src/black/linegen.py", "signals": ["same_component", "path_token_overlap"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"src/black/linegen.py": ["black"]}}, "merged_at": "2026-10-10T03:18:05Z", "pr": 5504, "ripple_relation": ["same_component", "path_token_overlap"], "source_pr": "https://github.com/psf/black/pull/5504"}, "query": {"anchor_diff": "@@ -416,6 +416,16 @@ def whitespace(leaf: Leaf, *, complex_subscript: bool, mode: Mode) -> str:\n if t == token.STAR:\n return NO\n \n+ elif p.type == syms.typeparams:\n+ # PEP 695 type parameter lists hug the preceding name\n+ if t == token.LSQB:\n+ return NO\n+\n+ elif p.type in {syms.typevartuple, syms.paramspec}:\n+ # PEP 695 `*Ts` and `**P`\n+ if prev and prev.type in STARS:\n+ return NO\n+\n if Preview.simplify_power_operator_hugging in mode:\n # Power operator hugging\n if t == token.DOUBLESTAR and is_simple_exponentiation(p):", "anchor_file": "src/black/nodes.py", "intent": "Handle PEP 695 type parameter whitespace in whitespace()\n\n`visit_typeparams`, `visit_typevartuple`, and `visit_paramspec` removed the space after `[`, `*`, and `**` by clearing the leaf prefix after `visit_default` had appended it. That only works for the lines built by `LineGenerator`: whenever a transformer rebuilds a line through `append_leaves` without `preformatted=True`, `whitespace()` runs again and reinstates the space. The unstable `string_processing` feature does exactly that when it splits a string inside a type parameter default, producing\n\n```python\ndef f[\n * Ts = Set[\n \"...\"\n \" ...\"\n ]\n]():\n```\n\nTeach `whitespace()` the three cases directly, which is where every other bracket and vararg rule lives, and drop the post-hoc prefix fixups. Stable output is unchanged; the existing `type_params.py` and `type_param_defaults.py` cases cover the simple forms, and the new case covers the rebuilt-line path.\n\nHandle PEP 695 type parameter whitespace in whitespace()"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "c9b1148b5b8799758756cbec7c0d1ac187d37f1a", "candidate_corpus": {"base_commit": "c9b1148b5b8799758756cbec7c0d1ac187d37f1a", "type": "repo_at_base_commit"}, "gold": {"files": ["src/black/nodes.py"], "given_files": ["src/black/linegen.py"]}, "id": "928394ba88ab8f1623fc4f7f", "metadata": {"changed_files": ["CHANGES.md", "src/black/linegen.py", "src/black/nodes.py", "tests/data/cases/preview_type_param_defaults_string_split.py"], "created_at": "2026-10-09T17:07:54Z", "fix_commit": "c45f21d0399747189eedcc6c9a1614b3cf49dc0f", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 10, "deletions": 0, "is_test": false, "path": "src/black/nodes.py", "signals": ["same_component", "path_token_overlap"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"src/black/nodes.py": ["black"]}}, "merged_at": "2026-10-10T03:18:05Z", "pr": 5504, "ripple_relation": ["same_component", "path_token_overlap"], "source_pr": "https://github.com/psf/black/pull/5504"}, "query": {"anchor_diff": "@@ -250,18 +250,6 @@ class LineGenerator(Visitor[Line]):\n \n yield from self.visit(child)\n \n- def visit_typeparams(self, node: Node) -> Iterator[Line]:\n- yield from self.visit_default(node)\n- node.children[0].prefix = \"\"\n-\n- def visit_typevartuple(self, node: Node) -> Iterator[Line]:\n- yield from self.visit_default(node)\n- node.children[1].prefix = \"\"\n-\n- def visit_paramspec(self, node: Node) -> Iterator[Line]:\n- yield from self.visit_default(node)\n- node.children[1].prefix = \"\"\n-\n def visit_dictsetmaker(self, node: Node) -> Iterator[Line]:\n if Preview.wrap_long_dict_values_in_parens in self.mode:\n for i, child in enumerate(node.children):", "anchor_file": "src/black/linegen.py", "intent": "Handle PEP 695 type parameter whitespace in whitespace()\n\n`visit_typeparams`, `visit_typevartuple`, and `visit_paramspec` removed the space after `[`, `*`, and `**` by clearing the leaf prefix after `visit_default` had appended it. That only works for the lines built by `LineGenerator`: whenever a transformer rebuilds a line through `append_leaves` without `preformatted=True`, `whitespace()` runs again and reinstates the space. The unstable `string_processing` feature does exactly that when it splits a string inside a type parameter default, producing\n\n```python\ndef f[\n * Ts = Set[\n \"...\"\n \" ...\"\n ]\n]():\n```\n\nTeach `whitespace()` the three cases directly, which is where every other bracket and vararg rule lives, and drop the post-hoc prefix fixups. Stable output is unchanged; the existing `type_params.py` and `type_param_defaults.py` cases cover the simple forms, and the new case covers the rebuilt-line path.\n\nHandle PEP 695 type parameter whitespace in whitespace()"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "6969cd9c869e3743444b96e861cc7c31d02e0263", "candidate_corpus": {"base_commit": "6969cd9c869e3743444b96e861cc7c31d02e0263", "type": "repo_at_base_commit"}, "gold": {"files": ["src/middleware/basic-auth/index.ts", "src/middleware/bearer-auth/index.ts", "src/utils/buffer.test.ts"], "given_files": ["src/utils/buffer.ts"]}, "id": "de5a27807cfa332268818147", "metadata": {"changed_files": ["docs/MIGRATION.md", "src/middleware/basic-auth/index.ts", "src/middleware/bearer-auth/index.ts", "src/utils/buffer.test.ts", "src/utils/buffer.ts"], "created_at": "2026-10-02T09:45:04Z", "fix_commit": "0d71f60ddffff089e6fa3c658730e3a0a7e1e5e1", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 4, "deletions": 3, "is_test": false, "path": "src/middleware/basic-auth/index.ts", "signals": ["gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 4, "deletions": 3, "is_test": false, "path": "src/middleware/bearer-auth/index.ts", "signals": ["gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 0, "deletions": 29, "is_test": true, "path": "src/utils/buffer.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"src/utils/buffer.test.ts": ["buffer"]}}, "merged_at": "2026-10-02T09:49:04Z", "pr": 5502, "ripple_relation": ["gold_diff_mentions_anchor_module", "shared_changed_symbol", "path_token_overlap", "optional_test_ripple"], "source_pr": "https://github.com/honojs/hono/pull/5502"}, "query": {"anchor_diff": "@@ -39,9 +39,9 @@ const constantTimeEqualString = (a: string, b: string): boolean => {\n return out === 0\n }\n \n-type StringHashFunction = (input: string) => string | null | Promise\n+export type StringHashFunction = (input: string) => string | null | Promise\n \n-const timingSafeEqualString = async (\n+export const timingSafeEqual = async (\n a: string,\n b: string,\n hashFunction?: StringHashFunction\n@@ -62,39 +62,6 @@ const timingSafeEqualString = async (\n return hashEqual && originalEqual\n }\n \n-type TimingSafeEqual = {\n- (a: string, b: string, hashFunction?: StringHashFunction): Promise\n- /**\n- * @deprecated object and boolean signatures that take boolean as first and second arguments, and functions with signatures that take non-string arguments have been deprecated\n- */\n- (\n- a: string | object | boolean,\n- b: string | object | boolean,\n- hashFunction?: Function\n- ): Promise\n-}\n-export const timingSafeEqual: TimingSafeEqual = async (\n- a,\n- b,\n- hashFunction?: Function\n-): Promise => {\n- if (typeof a === 'string' && typeof b === 'string') {\n- return timingSafeEqualString(a, b, hashFunction as StringHashFunction)\n- }\n-\n- if (!hashFunction) {\n- hashFunction = sha256\n- }\n-\n- const [sa, sb] = await Promise.all([hashFunction(a), hashFunction(b)])\n-\n- if (!sa || !sb || typeof sa !== 'string' || typeof sb !== 'string') {\n- return false\n- }\n-\n- return timingSafeEqualString(sa, sb)\n-}\n-\n export const bufferToString = (buffer: ArrayBuffer): string => {\n if (buffer instanceof ArrayBuffer) {\n const enc = new TextDecoder('utf-8')", "anchor_file": "src/utils/buffer.ts", "intent": "chore!(utils): make timingSafeEqual string-only\n\n### The author should do the following, if applicable\n\n- [ ] Add tests\n- [x] Run tests\n- [x] `pnpm run check:fix` to format and lint the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code\n\nchore!(utils): make timingSafeEqual string-only"}, "repo": "honojs/hono", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "4fb2897a7ac539cc14d993e3697469e2529a265e", "candidate_corpus": {"base_commit": "4fb2897a7ac539cc14d993e3697469e2529a265e", "type": "repo_at_base_commit"}, "gold": {"files": ["src/black/mode.py", "src/black/resources/black.schema.json"], "given_files": ["src/black/linegen.py"]}, "id": "96c810da922cc1f37fd0a228", "metadata": {"changed_files": ["CHANGES.md", "docs/the_black_code_style/future_style.md", "src/black/linegen.py", "src/black/mode.py", "src/black/resources/black.schema.json", "tests/data/cases/preview_keep_trailers_on_bracket_comment_overflow.py"], "created_at": "2026-10-08T11:57:37Z", "fix_commit": "fe241ccc443acbabbd75c8240d2fbc06ba4e52d6", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 0, "is_test": false, "path": "src/black/mode.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 2, "deletions": 1, "is_test": false, "path": "src/black/resources/black.schema.json", "signals": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"src/black/mode.py": ["mode", "black"], "src/black/resources/black.schema.json": ["black"]}}, "merged_at": "2026-10-10T03:46:30Z", "pr": 5498, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"], "source_pr": "https://github.com/psf/black/pull/5498"}, "query": {"anchor_diff": "@@ -1067,7 +1067,12 @@ def right_hand_split_with_omits(\n # for simple cases. All others require running more transforms via\n # `transform_line()`. This check doesn't know if those would succeed.\n if is_line_short_enough(lines[0], mode=mode) or (\n- omit and _over_length_only_due_to_subscript_comment(lines[0], mode)\n+ omit\n+ and (\n+ _over_length_only_due_to_bracket_comment(lines[0], mode)\n+ if Preview.keep_trailers_on_bracket_comment_overflow in mode\n+ else _over_length_only_due_to_subscript_comment(lines[0], mode)\n+ )\n ):\n if (\n Preview.fix_magic_trailing_comma_trailer_split in mode\n@@ -2517,16 +2522,18 @@ def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[set[Leaf\n closing_bracket = leaf\n \n \n-def _over_length_only_due_to_subscript_comment(line: Line, mode: Mode) -> bool:\n+def _over_length_only_due_to_bracket_comment(\n+ line: Line, mode: Mode, allowed_brackets: Collection[int] = OPENING_BRACKETS\n+) -> bool:\n \"\"\"Return True if `line` only exceeds `mode.line_length` because of an inline\n- comment attached to a subscript opening bracket (`[`).\n-\n- This is the shape produced by the original of the issue #4733 reproducer:\n- a comment inside the annotation's subscript brackets renders at the end of\n- the head line after Black splits the statement, pushing it past the limit.\n- Taking the FORCE_OPTIONAL_PARENTHESES \"second opinion\" in that case wraps\n- the annotation in extra parens and migrates the comment outside the\n- subscript, which then oscillates on the next formatter pass.\n+ comment attached to an opening bracket.\n+\n+ This is the shape produced by issues #4733 and #3681:\n+ a comment inside brackets renders at the end of the head line after Black\n+ splits the statement, pushing it past the limit. If the line without the\n+ comment fits within `mode.line_length`, rejecting an omit-based split does\n+ not prevent the line from exceeding the limit and causes unnecessary\n+ splitting of other trailers (issue #3681).\n \"\"\"\n if not line.leaves:\n return False\n@@ -2538,16 +2545,22 @@ def _over_length_only_due_to_subscript_comment(line: Line, mode: Mode) -> bool:\n text_without_comments += \"\".join(str(leaf) for leaf in leaves_iter)\n if str_width(text_without_comments) > mode.line_length:\n return False\n- # And the comment must be attached to a subscript opening bracket.\n+ # And the comment must be attached to an opening bracket.\n for leaf_id, comments in line.comments.items():\n if not comments:\n continue\n leaf = next((lf for lf in line.leaves if id(lf) == leaf_id), None)\n- if leaf is None or leaf.type != token.LSQB:\n+ if leaf is None or leaf.type not in allowed_brackets:\n return False\n return True\n \n \n+def _over_length_only_due_to_subscript_comment(line: Line, mode: Mode) -> bool:\n+ return _over_length_only_due_to_bracket_comment(\n+ line, mode, allowed_brackets={token.LSQB}\n+ )\n+\n+\n def run_transformer(\n line: Line,\n transform: Transformer,", "anchor_file": "src/black/linegen.py", "intent": "Avoid splitting trailers when earlier bracket split exceeds length due to comments (#3681)\n\n## Summary\n\nFixes #3681.\n\nWhen a line containing an opening parenthesis/bracket is split, but the resulting head line exceeds `line_length` solely because of a trailing comment (e.g. `# type: ignore`), `right_hand_split_with_omits` previously rejected the split and fell back to `first_lines` (no omits). This caused unrelated trailing indexing/subscripts (such as `[0]`) on later lines to be exploded across multiple lines, even though the head line could not be shortened by splitting them and ended up exceeding the limt regardless.\n\n## Changes\n\n- Updated `_over_length_only_due_to_bracket_comment` in `src/black/linegen.py` to allow any opening bracket in `OPENING_BRACKETS` (`(`, `[`, `{`) when evaluating omit candidates in `right_hand_split_with_omits`.\n- Retained the subscript-specific check (`token.LSQB`) for `run_transformer` to preserve behavior for assignments and prevent comment-migration oscillations.\n- Added regression tests in `tests/data/cases/comment_on_opening_bracket.py`.\n- Added a changelog entry to `CHANGES.md`.\n\n## Test Plan\n\n- `pytest tests/test_format.py -k \"comment_on_opening_bracket\"`\n- Full pytest test suite (`pytest tests/`) passes cleanly.\n- `flake8`, `mypy`, and `black --check` all pass.\n\nAvoid splitting trailers when earlier bracket split exceeds length due to comments (#3681)\n\nUpdate CHANGES.md with PR #5498\n\nMove keep_trailers_on_bracket_comment_overflow to preview style\n\n[pre-commit.ci] auto fixes from pre-commit.com hooks\n\nMerge branch 'main' into fix-type-ignore-subscript-split-3681"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "c9b1148b5b8799758756cbec7c0d1ac187d37f1a", "candidate_corpus": {"base_commit": "c9b1148b5b8799758756cbec7c0d1ac187d37f1a", "type": "repo_at_base_commit"}, "gold": {"files": ["tests/test_black.py"], "given_files": ["src/black/files.py"]}, "id": "05572da1866418afe11b347f", "metadata": {"changed_files": ["CHANGES.md", "src/black/files.py", "tests/test_black.py"], "created_at": "2026-10-08T11:24:10Z", "fix_commit": "8ec61a7fb6f1961377afd28bbe71f8a2095916ac", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 18, "deletions": 0, "is_test": true, "path": "tests/test_black.py", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"tests/test_black.py": ["black"]}}, "merged_at": "2026-10-10T03:15:14Z", "pr": 5497, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/psf/black/pull/5497"}, "query": {"anchor_diff": "@@ -258,7 +258,9 @@ def get_gitignore(root: Path | None) -> GitIgnoreSpec:\n gitignore = root / \".gitignore\"\n lines: list[str] = []\n if gitignore.is_file():\n- with gitignore.open(encoding=\"utf-8\") as gf:\n+ # Like git, skip a UTF-8 byte order mark. Otherwise it becomes part of the\n+ # first pattern, which then never matches.\n+ with gitignore.open(encoding=\"utf-8-sig\") as gf:\n lines = gf.readlines()\n try:\n return GitIgnoreSpec.from_lines(lines)", "anchor_file": "src/black/files.py", "intent": "Skip UTF-8 BOM when reading .gitignore\n\n### Description\n\nIf a .gitignore starts with a UTF-8 BOM, Black ignores the first\npattern in it. Git skips the BOM so the pattern still works there,\nbut Black reads it as part of the pattern, so it never matches. So\nBlack ends up formatting files that git ignores.\n\nSome editors and tools on Windows save files with a BOM.\n\nTo reproduce:\n\n```sh\nmkdir demo && cd demo && git init\nmkdir generated\nprintf '\\xef\\xbb\\xbfgenerated/\\n' > .gitignore\nprintf 'x = 1\\n' > generated/models.py\ngit check-ignore generated/models.py # git says it is ignored\nblack --check . # black wants to reformat generated/models.py\n```\n\nThe fix opens .gitignore with utf-8-sig instead of utf-8. That drops\nthe BOM if there is one and reads normal UTF-8 files the same as\nbefore. I added a test with a BOM in both a root and a nested\n.gitignore.\n\n### Checklist - did you ...\n\n- [x] Implement any code style changes under the `--preview` style, following the stability policy?\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests if necessary?\n- [x] Add new / update outdated documentation?\n\nSkip UTF-8 BOM when reading .gitignore"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "1ed66a8b3385a000508a03158ac3dc2a8a75a209", "candidate_corpus": {"base_commit": "1ed66a8b3385a000508a03158ac3dc2a8a75a209", "type": "repo_at_base_commit"}, "gold": {"files": ["src/black/__init__.py", "tests/test_black.py", "tests/test_ranges.py"], "given_files": ["src/black/ranges.py"]}, "id": "803b834c5f1119e958344392", "metadata": {"changed_files": ["CHANGES.md", "src/black/__init__.py", "src/black/ranges.py", "tests/test_black.py", "tests/test_ranges.py"], "created_at": "2026-10-05T05:05:57Z", "fix_commit": "77c0cae18bcc82257882afc7bbb9a5cd95cba16c", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 5, "deletions": 0, "is_test": false, "path": "src/black/__init__.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 31, "deletions": 0, "is_test": true, "path": "tests/test_black.py", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 34, "deletions": 1, "is_test": true, "path": "tests/test_ranges.py", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"src/black/__init__.py": ["black"], "tests/test_black.py": ["black"], "tests/test_ranges.py": ["ranges"]}}, "merged_at": "2026-10-05T17:42:53Z", "pr": 5484, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/psf/black/pull/5484"}, "query": {"anchor_diff": "@@ -593,10 +593,13 @@ def _calculate_lines_mappings(\n original_source: the original source.\n modified_source: the modified source.\n \"\"\"\n+ # The first formatting pass re-indents the bodies of the statements it\n+ # formats, so the same line can have a different indentation in the two\n+ # sources. Comparing the lines without indentation keeps them matched.\n matcher = difflib.SequenceMatcher(\n None,\n- original_source.splitlines(keepends=True),\n- modified_source.splitlines(keepends=True),\n+ [line.strip() for line in original_source.splitlines(keepends=True)],\n+ [line.strip() for line in modified_source.splitlines(keepends=True)],\n )\n matching_blocks = matcher.get_matching_blocks()\n lines_mappings: list[_LinesMapping] = []\n@@ -615,7 +618,10 @@ def _calculate_lines_mappings(\n original_end=block.a,\n modified_start=1,\n modified_end=block.b,\n- is_changed_block=False,\n+ # The lines before the first matching block are not part of\n+ # any matching block, so this range is a changed block. A line\n+ # that only exists on one side has no counterpart to map onto.\n+ is_changed_block=True,\n )\n )\n else:", "anchor_file": "src/black/ranges.py", "intent": "Fix line-range mapping for a changed start of file\n\n### Description\n\nPart of #4052. Two things kept `--line-ranges` from selecting the right lines when\nthe first formatting pass rewrote the start of a file.\n\n**1. The lines before the first matching block were recorded as an *unchanged* block**\n\n`_calculate_lines_mappings` marked that region as unchanged even though those lines\nhave no counterpart on the other side of the diff. A requested range that overlaps\nthem was therefore mapped by offset instead of being expanded to the changed block,\nwhich is what every other changed block does, and what `adjusted_lines`' docstring\ndocuments.\n\n**2. Lines were compared verbatim**\n\nThe first pass re-indents the bodies of the statements it formats, so a line that\nonly moved within its statement looked like an unrelated change. That turned the\nwhole file into a single leading block, and mapping the range stayed a no-op. The\ncomparison ignores leading whitespace now: a line that only moved is still the same\nline, and `_LinesMapping` only records where it went.\n\nTogether they fix the first case of the issue:\n\n```python\ndef restrict_to_this_line(arg1,\n arg2,\n arg3):\n print ( \"This should not be formatted.\" )\n print ( \"This should not be formatted.\" )\n```\n\nWith `--line-ranges=1-3`, before: the signature is joined **and** both `print`\nstatements are formatted, although they were never selected. After: the signature is\njoined, and the `print` statements keep the indentation given by the first pass\nwithout being formatted.\n\nThe lines before the first matching block can also disappear entirely, because Black\ndrops leading empty lines; a selection that only covers them then maps to nothing.\n`format_str` passed those empty ranges to the second pass, where an empty `lines`\nmeans \"format t\n...[truncated]"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "1ed66a8b3385a000508a03158ac3dc2a8a75a209", "candidate_corpus": {"base_commit": "1ed66a8b3385a000508a03158ac3dc2a8a75a209", "type": "repo_at_base_commit"}, "gold": {"files": ["src/black/ranges.py", "tests/test_black.py", "tests/test_ranges.py"], "given_files": ["src/black/__init__.py"]}, "id": "d6422e1307af36f2272b156b", "metadata": {"changed_files": ["CHANGES.md", "src/black/__init__.py", "src/black/ranges.py", "tests/test_black.py", "tests/test_ranges.py"], "created_at": "2026-10-05T05:05:57Z", "fix_commit": "77c0cae18bcc82257882afc7bbb9a5cd95cba16c", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 9, "deletions": 3, "is_test": false, "path": "src/black/ranges.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 31, "deletions": 0, "is_test": true, "path": "tests/test_black.py", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 34, "deletions": 1, "is_test": true, "path": "tests/test_ranges.py", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"src/black/ranges.py": ["ranges", "black"], "tests/test_black.py": ["black"], "tests/test_ranges.py": ["ranges"]}}, "merged_at": "2026-10-05T17:42:53Z", "pr": 5484, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/psf/black/pull/5484"}, "query": {"anchor_diff": "@@ -1360,6 +1360,11 @@ def format_str(\n if src_contents != dst_contents:\n if lines:\n lines = adjusted_lines(lines, src_contents, dst_contents)\n+ if not lines:\n+ # None of the requested lines survived the first pass, so there is\n+ # nothing left to format. Passing the empty `lines` to the second\n+ # pass would format the whole file instead.\n+ return dst_contents\n try:\n dst_contents = _format_str_once(dst_contents, mode=mode, lines=lines)\n except InvalidInput as exc:", "anchor_file": "src/black/__init__.py", "intent": "Fix line-range mapping for a changed start of file\n\n### Description\n\nPart of #4052. Two things kept `--line-ranges` from selecting the right lines when\nthe first formatting pass rewrote the start of a file.\n\n**1. The lines before the first matching block were recorded as an *unchanged* block**\n\n`_calculate_lines_mappings` marked that region as unchanged even though those lines\nhave no counterpart on the other side of the diff. A requested range that overlaps\nthem was therefore mapped by offset instead of being expanded to the changed block,\nwhich is what every other changed block does, and what `adjusted_lines`' docstring\ndocuments.\n\n**2. Lines were compared verbatim**\n\nThe first pass re-indents the bodies of the statements it formats, so a line that\nonly moved within its statement looked like an unrelated change. That turned the\nwhole file into a single leading block, and mapping the range stayed a no-op. The\ncomparison ignores leading whitespace now: a line that only moved is still the same\nline, and `_LinesMapping` only records where it went.\n\nTogether they fix the first case of the issue:\n\n```python\ndef restrict_to_this_line(arg1,\n arg2,\n arg3):\n print ( \"This should not be formatted.\" )\n print ( \"This should not be formatted.\" )\n```\n\nWith `--line-ranges=1-3`, before: the signature is joined **and** both `print`\nstatements are formatted, although they were never selected. After: the signature is\njoined, and the `print` statements keep the indentation given by the first pass\nwithout being formatted.\n\nThe lines before the first matching block can also disappear entirely, because Black\ndrops leading empty lines; a selection that only covers them then maps to nothing.\n`format_str` passed those empty ranges to the second pass, where an empty `lines`\nmeans \"format t\n...[truncated]"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "30664d8f17b29658aa72e44a1bfe23eede12db99", "candidate_corpus": {"base_commit": "30664d8f17b29658aa72e44a1bfe23eede12db99", "type": "repo_at_base_commit"}, "gold": {"files": ["tests/test_ipynb.py"], "given_files": ["src/black/handle_ipynb_magics.py"]}, "id": "e97cdeef0349843cfb484be8", "metadata": {"changed_files": ["CHANGES.md", "src/black/handle_ipynb_magics.py", "tests/test_ipynb.py"], "created_at": "2026-10-04T18:11:02Z", "fix_commit": "f4f6cd9becdafb8e88dfff171ad4bb91427864c8", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 36, "deletions": 0, "is_test": true, "path": "tests/test_ipynb.py", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"tests/test_ipynb.py": ["ipynb"]}}, "merged_at": "2026-10-05T03:46:22Z", "pr": 5481, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/psf/black/pull/5481"}, "query": {"anchor_diff": "@@ -323,6 +323,15 @@ def unmask_cell(src: str, replacements: list[Replacement]) -> str:\n if src.count(replacement.mask) != 1:\n raise NothingChanged\n src = src.replace(replacement.mask, replacement.src, 1)\n+ if replacements:\n+ # Formatting can move a mask to where IPython no longer recognises the\n+ # magic, e.g. into the parentheses around a long right-hand side.\n+ try:\n+ _, unmasked_replacements = mask_cell(src)\n+ except SyntaxError:\n+ raise NothingChanged from None\n+ if [r.src for r in unmasked_replacements] != [r.src for r in replacements]:\n+ raise NothingChanged\n return src", "anchor_file": "src/black/handle_ipynb_magics.py", "intent": "Fix long notebook magic assignments being wrapped in parentheses\n\n### Description\n\nWhen a notebook cell has a magic assignment that is longer than the line length, Black\nwraps it in parentheses. For example this cell:\n\n```python\ninstalled_packages_in_this_environment = !pip list --format=freeze --disable-pip-version-check\n```\n\nbecomes:\n\n```python\ninstalled_packages_in_this_environment = (\n !pip list --format=freeze --disable-pip-version-check\n)\n```\n\nIPython does not accept a magic inside parentheses, so the cell now fails with\n`SyntaxError: invalid syntax` when you run it. Black exits with 0, and later runs of\n`black --check` also pass because Black skips the broken cell.\n\nThe reason is that Black formats the cell with each magic replaced by a placeholder\nstring. The placeholder can be wrapped like any other string, and the safety check only\nsees the placeholder version, so it does not notice the problem.\n\nThe fix is in `unmask_cell`. After the magics are put back, it masks the cell again and\nchecks that IPython still finds the same magics. If it does not, the cell is left\nunchanged, the same way Black already skips cells it cannot format safely.\n\nI added tests for a long `!` assignment, a long `%timeit -o` assignment, an indented one,\nand a direct test for `unmask_cell`. All of them fail without the fix.\n\n### Checklist - did you ...\n\n- [x] Implement any code style changes under the `--preview` style, following the stability policy?\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests if necessary?\n- [x] Add new / update outdated documentation?\n\nFix long notebook magic assignments being wrapped in parentheses\n\nRe-run CI\n\nMerge branch 'main' into fix-ipynb-magic-parens"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "ee05651742abc47ec807c0fb34247ac6f4f3c5fc", "candidate_corpus": {"base_commit": "ee05651742abc47ec807c0fb34247ac6f4f3c5fc", "type": "repo_at_base_commit"}, "gold": {"files": ["tests/test_black.py"], "given_files": ["src/black/__init__.py"]}, "id": "34c6e9a81a20fe49cc0e0da5", "metadata": {"changed_files": ["CHANGES.md", "src/black/__init__.py", "tests/test_black.py"], "created_at": "2026-10-03T07:37:37Z", "fix_commit": "97fb59f06a076fa34c68b2922b4d3da583adfa90", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 15, "deletions": 0, "is_test": true, "path": "tests/test_black.py", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"tests/test_black.py": ["black"]}}, "merged_at": "2026-10-05T17:32:32Z", "pr": 5476, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/psf/black/pull/5476"}, "query": {"anchor_diff": "@@ -1023,9 +1023,15 @@ def reformat_one(\n src, fast=fast, write_back=write_back, mode=mode, lines=lines\n ):\n changed = Changed.YES\n- if cache is not None and (\n- (write_back is WriteBack.YES and changed is not Changed.CACHED)\n- or (write_back is WriteBack.CHECK and changed is Changed.NO)\n+ # Formatting only some lines doesn't make the whole file formatted, and\n+ # the cache key doesn't include the line ranges, so don't record it.\n+ if (\n+ cache is not None\n+ and not lines\n+ and (\n+ (write_back is WriteBack.YES and changed is not Changed.CACHED)\n+ or (write_back is WriteBack.CHECK and changed is Changed.NO)\n+ )\n ):\n cache.write([src])\n report.done(src, changed)", "anchor_file": "src/black/__init__.py", "intent": "Fix check passing after a line ranges run\n\n### Description\n\nFixes #5474\n\nWhen black runs with `--line-ranges` it still saves the file in the cache as if the whole file was formatted\n\nAfter that a normal `black --check` trusts the cache and exits 0 even though the rest of the file is not formatted and a plain `black` run skips the file too\n\nThis change skips the cache write in `reformat_one` when line ranges are used\n\nReading the cache stays the same since a fully formatted file is still fine for any range\n\nI added a test that covers both the format case and the check case\n\n### Checklist - did you ...\n\n- [x] Implement any code style changes under the `--preview` style, following the stability policy?\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests if necessary?\n- [x] Add new / update outdated documentation?\n\nDon't cache files formatted with --line-ranges\n\nAdd PR number to changelog\n\nMerge branch 'main' into fix-line-ranges-cache-poisoning"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "a3cb9e123ceab4f0fcab4980dd6c5f9439646794", "candidate_corpus": {"base_commit": "a3cb9e123ceab4f0fcab4980dd6c5f9439646794", "type": "repo_at_base_commit"}, "gold": {"files": ["tests/test_black.py"], "given_files": ["src/black/linegen.py"]}, "id": "f56b3b3eea42f2ce80db5372", "metadata": {"changed_files": ["CHANGES.md", "src/black/linegen.py", "tests/test_black.py"], "created_at": "2026-10-03T07:31:25Z", "fix_commit": "27c6fd024f97408bd0ab8e01c5dd72c0b927035e", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 13, "deletions": 0, "is_test": true, "path": "tests/test_black.py", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"tests/test_black.py": ["black"]}}, "merged_at": "2026-10-06T18:04:33Z", "pr": 5475, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/psf/black/pull/5475"}, "query": {"anchor_diff": "@@ -1044,8 +1044,34 @@ def right_hand_split_with_omits(\n bracket pair instead.\n \"\"\"\n fallback_omit: set[LeafID] | None = None\n+ first_lines: list[Line] | None = None\n+\n+ prefix_lengths: dict[LeafID, int] = {}\n+ curr_len = 4 * line.depth\n+ for leaf in line.leaves:\n+ prefix_lengths[id(leaf)] = curr_len\n+ curr_len += len(leaf.prefix) + len(leaf.value)\n+\n for omit in generate_trailers_to_omit(line, mode.line_length):\n+ if omit:\n+ target_opening: Leaf | None = None\n+ for leaf in reversed(line.leaves):\n+ if leaf.type in CLOSING_BRACKETS and id(leaf) not in omit:\n+ target_opening = leaf.opening_bracket\n+ break\n+ # If the candidate split point is a concrete bracket whose prefix length\n+ # from the start of the line already exceeds line_length, the head line\n+ # is mathematically guaranteed to exceed line_length as well.\n+ if (\n+ target_opening is not None\n+ and target_opening.value\n+ and prefix_lengths.get(id(target_opening), 0) > mode.line_length\n+ ):\n+ continue\n+\n lines = list(right_hand_split(line, mode, features, omit=omit))\n+ if first_lines is None and not omit:\n+ first_lines = lines\n # Note: this check is only able to figure out if the first line of the\n # *current* transformation fits in the line length. This is true only\n # for simple cases. All others require running more transforms via\n@@ -1068,14 +1094,17 @@ def right_hand_split_with_omits(\n return\n \n if fallback_omit is not None:\n- yield from right_hand_split(line, mode, features, omit=fallback_omit)\n+ yield from right_hand_split(line, mode, features=features, omit=fallback_omit)\n return\n \n # All splits failed, best effort split with no omits.\n # This mostly happens to multiline strings that are by definition\n # reported as not fitting a single line, as well as lines that contain\n # trailing commas (those have to be exploded).\n- yield from right_hand_split(line, mode, features=features)\n+ if first_lines is not None:\n+ yield from first_lines\n+ else:\n+ yield from right_hand_split(line, mode, features=features)\n \n \n def _first_right_hand_split(", "anchor_file": "src/black/linegen.py", "intent": "Avoid quadratic runtime in right_hand_split_with_omits on long lines (#5270)\n\n## Summary\nFixes #5270.\nCloses #5275\nCloses #5305\n\nFormatting lines containing long chains of consecutive bracket trailers (such as subscript chains `a[0][1]...[160]`) suffered from quadratic runtime due to combinatorial omit trials in `right_hand_split_with_omits`.\n\n### Root Cause\nUnlike attribute chains which have dot delimiters and are split cleanly in a single pass by `delimiter_split`, consecutive\n subscript chains `][` have no intermediate delimiters and fall back to `right_hand_split_with_omits`.\n\n`generate_trailers_to_omit` yields bracket pairs from the tail up to `line_length`. In long lines with many small trailers\n (like `[0]...`), Black was performing up to 20 full `right_hand_split` calls per recursion level, only for\n `is_line_short_enough(lines[0])` to fail on every single omit candidate because each candidate split point was still hundreds of\n characters from the start of the line.\n\n### Fix\n1. Precompute cumulative prefix lengths for all leaves in `line.leaves` once at the start of `right_hand_split_with_omits`.\n2. For each candidate `omit`, inspect the target `opening_bracket` the split would break on. If its prefix length from the start of the line alone exceeds `mode.line_length`, any head line produced by that split is mathematically guaranteed to exceed `line_length`. We safely skip executing `right_hand_split` for that omit.\n3. Candidate omits that break on an opening bracket within `mode.line_length` (e.g. `foo(long_args...)[key]`) are retained and evaluated normally.\n4. In the final fallback, reuse `first_lines` instead of redundantly re-running `right_hand_split`.\n5. Output formatting is 100% invariant across all cases (diff-shades shows 0 changes).\n\n### Benchmark\n...[truncated]"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "30664d8f17b29658aa72e44a1bfe23eede12db99", "candidate_corpus": {"base_commit": "30664d8f17b29658aa72e44a1bfe23eede12db99", "type": "repo_at_base_commit"}, "gold": {"files": ["src/black/mode.py", "src/black/resources/black.schema.json"], "given_files": ["src/black/linegen.py"]}, "id": "a24613cd6de5673a55be06da", "metadata": {"changed_files": ["CHANGES.md", "docs/the_black_code_style/future_style.md", "scripts/diff_shades_gha_helper.py", "src/black/linegen.py", "src/black/mode.py", "src/black/resources/black.schema.json", "tests/data/cases/preview_avoid_parens_for_unbreakable_rhs_in_assignments.py"], "created_at": "2026-10-03T04:44:16Z", "fix_commit": "99d9cbfd80e76f8581d1d370c1063cf4abe6c9b3", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 0, "is_test": false, "path": "src/black/mode.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 2, "deletions": 1, "is_test": false, "path": "src/black/resources/black.schema.json", "signals": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"src/black/mode.py": ["mode", "black"], "src/black/resources/black.schema.json": ["black"]}}, "merged_at": "2026-10-05T03:37:35Z", "pr": 5473, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"], "source_pr": "https://github.com/psf/black/pull/5473"}, "query": {"anchor_diff": "@@ -1222,6 +1222,10 @@ def _maybe_split_omitting_optional_parens(\n rhs_oop, line, mode, features=features, omit=omit\n )\n return\n+ elif Preview.avoid_parens_for_unbreakable_rhs_in_assignments in mode:\n+ raise CannotSplit(\n+ \"Alternative split not preferred, falling back to original RHS\"\n+ )\n \n except CannotSplit as e:\n # For chained assignments we want to use the previous successful split", "anchor_file": "src/black/linegen.py", "intent": "Avoid unnecessary parens for unbreakable RHS in assignments (#3954)\n\nFixes #3954 \n \n### Summary \nWhen an assignment's target contains type\n annotations or brackets (e.g. `attr: str = \"long...\"`\nor `a[0] = \"long...\"`) and the RHS \n is an unbreakable expression (like a long \n string or identifier) that cannot fit within \n the line length limit even with parentheses, \n Black previously wrapped the RHS in outer \n parentheses, creating an inconsistency with \n standard unannotated assignments (`attr = \"long...\"`). \n \nThis happened because \n `_maybe_split_omitting_optional_parens` found \n an alternative split on the LHS \n brackets/invisible parens (`rhs_oop`), rejected\n it via `_prefer_split_rhs_oop_over_rhs`, but \n then bypassed the validation check that \n verifies whether the original RHS body can \n actually be split or fit on one line. \n \nUnder `--preview`, Black now recognizes that \n the alternative split was rejected and falls \n back to validating the original RHS, leaving \n unbreakable expressions unparenthesized when \n wrapping cannot satisfy the line length.\n\nAvoid unnecessary parens for unbreakable RHS in assignments (#3954)\n\nMerge branch 'main' into fix-annotated-string-parens-3954"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "30664d8f17b29658aa72e44a1bfe23eede12db99", "candidate_corpus": {"base_commit": "30664d8f17b29658aa72e44a1bfe23eede12db99", "type": "repo_at_base_commit"}, "gold": {"files": ["src/black/resources/black.schema.json", "src/black/linegen.py"], "given_files": ["src/black/mode.py"]}, "id": "b965017b2ba2950fffda739f", "metadata": {"changed_files": ["CHANGES.md", "docs/the_black_code_style/future_style.md", "scripts/diff_shades_gha_helper.py", "src/black/linegen.py", "src/black/mode.py", "src/black/resources/black.schema.json", "tests/data/cases/preview_avoid_parens_for_unbreakable_rhs_in_assignments.py"], "created_at": "2026-10-03T04:44:16Z", "fix_commit": "99d9cbfd80e76f8581d1d370c1063cf4abe6c9b3", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 2, "deletions": 1, "is_test": false, "path": "src/black/resources/black.schema.json", "signals": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"]}, {"additions": 4, "deletions": 0, "is_test": false, "path": "src/black/linegen.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"src/black/linegen.py": ["black"], "src/black/resources/black.schema.json": ["black"]}}, "merged_at": "2026-10-05T03:37:35Z", "pr": 5473, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema", "same_component"], "source_pr": "https://github.com/psf/black/pull/5473"}, "query": {"anchor_diff": "@@ -270,6 +270,7 @@ class Preview(Enum):\n fix_magic_trailing_comma_trailer_split = auto()\n keep_dict_keys_with_operators = auto()\n blank_line_after_stub_method = auto()\n+ avoid_parens_for_unbreakable_rhs_in_assignments = auto()\n \n \n UNSTABLE_FEATURES: set[Preview] = {", "anchor_file": "src/black/mode.py", "intent": "Avoid unnecessary parens for unbreakable RHS in assignments (#3954)\n\nFixes #3954 \n \n### Summary \nWhen an assignment's target contains type\n annotations or brackets (e.g. `attr: str = \"long...\"`\nor `a[0] = \"long...\"`) and the RHS \n is an unbreakable expression (like a long \n string or identifier) that cannot fit within \n the line length limit even with parentheses, \n Black previously wrapped the RHS in outer \n parentheses, creating an inconsistency with \n standard unannotated assignments (`attr = \"long...\"`). \n \nThis happened because \n `_maybe_split_omitting_optional_parens` found \n an alternative split on the LHS \n brackets/invisible parens (`rhs_oop`), rejected\n it via `_prefer_split_rhs_oop_over_rhs`, but \n then bypassed the validation check that \n verifies whether the original RHS body can \n actually be split or fit on one line. \n \nUnder `--preview`, Black now recognizes that \n the alternative split was rejected and falls \n back to validating the original RHS, leaving \n unbreakable expressions unparenthesized when \n wrapping cannot satisfy the line length.\n\nAvoid unnecessary parens for unbreakable RHS in assignments (#3954)\n\nMerge branch 'main' into fix-annotated-string-parens-3954"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "994ef7eeb18172178552daa1f36f001d156ad583", "candidate_corpus": {"base_commit": "994ef7eeb18172178552daa1f36f001d156ad583", "type": "repo_at_base_commit"}, "gold": {"files": ["tests/test_black.py"], "given_files": ["src/black/files.py"]}, "id": "dfbe4a43112dbf7e7106f7a4", "metadata": {"changed_files": ["CHANGES.md", "src/black/files.py", "tests/test_black.py"], "created_at": "2026-10-02T11:22:06Z", "fix_commit": "e1c478359c087b76a6c4830a84c7e78ac93d8a6c", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 59, "deletions": 0, "is_test": true, "path": "tests/test_black.py", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"tests/test_black.py": ["black"]}}, "merged_at": "2026-10-03T21:30:52Z", "pr": 5471, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/psf/black/pull/5471"}, "query": {"anchor_diff": "@@ -291,15 +291,28 @@ def resolves_outside_root_or_cannot_stat(\n return False\n \n \n+def _collapse_parent_dirs(relative_path: Path) -> Path:\n+ \"\"\"Collapse \"..\" in a root-relative path without resolving symlinks.\n+\n+ This way exclusion regexes see \"generated/x.py\" rather than\n+ \"src/../generated/x.py\". If a symlink makes the collapsed path leave the\n+ root, the path is kept as given.\n+ \"\"\"\n+ collapsed = Path(os.path.normpath(relative_path))\n+ if collapsed.parts[:1] == (\"..\",):\n+ return relative_path\n+ return collapsed\n+\n+\n def best_effort_relative_path(path: Path, root: Path) -> Path:\n # Precondition: resolves_outside_root_or_cannot_stat(path, root) is False\n try:\n- return path.absolute().relative_to(root)\n+ return _collapse_parent_dirs(path.absolute().relative_to(root))\n except ValueError:\n pass\n root_parent = next((p for p in path.parents if _cached_resolve(p) == root), None)\n if root_parent is not None:\n- return path.relative_to(root_parent)\n+ return _collapse_parent_dirs(path.relative_to(root_parent))\n # something adversarial, fallback to path guaranteed by precondition\n return _cached_resolve(path).relative_to(root)", "anchor_file": "src/black/files.py", "intent": "Fix --force-exclude for paths containing ..\n\n### Description\n\nFixes #5470\n\nWhen a file path has `..` in it `--force-exclude` does not match it so the excluded file still gets formatted. For example with `force-exclude = \"^/generated/\"` running `black ../generated/gen.py` from `src/` reformats `generated/gen.py`. The same happens with `--stdin-filename`\n\n`best_effort_relative_path` used `path.absolute()` which keeps the `..` so the regex was checked against `/src/../generated/gen.py` and not `/generated/gen.py`\n\nThis PR collapses the `..` with `os.path.normpath` before the check. It does not resolve symlinks so the current symlink behaviour stays the same. If a symlink makes the collapsed path leave the project root the path is kept as given so that case works like before\n\nI added two tests. One for `..` paths (a file path and stdin) and one for the symlink case\n\n### Checklist - did you ...\n\n- [x] Implement any code style changes under the `--preview` style, following the stability policy?\n- [x] Add an entry in `CHANGES.md` if necessary?\n- [x] Add / update tests if necessary?\n- [x] Add new / update outdated documentation?\n\nFix --force-exclude for paths containing ..\n\nAdd PR number to changelog\n\nFix new tests on Windows and mypy"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "f3d5e8856244eb5faf9e1322834ca1639134d971", "candidate_corpus": {"base_commit": "f3d5e8856244eb5faf9e1322834ca1639134d971", "type": "repo_at_base_commit"}, "gold": {"files": ["adapters/netlify/src/mod.ts", "adapters/netlify/src/index.ts", "adapters/netlify/tsconfig.json", "adapters/netlify/src/conninfo.test.ts"], "given_files": ["adapters/netlify/src/conninfo.ts"]}, "id": "b833a68e35ba28728a57aca3", "metadata": {"changed_files": ["adapters/netlify/README.md", "adapters/netlify/deno.json", "adapters/netlify/src/conninfo.test.ts", "adapters/netlify/src/conninfo.ts", "adapters/netlify/src/index.ts", "adapters/netlify/src/mod.ts", "adapters/netlify/tsconfig.json", "docs/MAINTAINING.md"], "created_at": "2026-09-28T08:35:01Z", "fix_commit": "72f0d8d58e20547c25370a97191765a9ca0e1d9b", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 2, "deletions": 2, "is_test": false, "path": "adapters/netlify/src/mod.ts", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 1, "deletions": 1, "is_test": false, "path": "adapters/netlify/src/index.ts", "signals": ["same_component", "path_token_overlap"]}, {"additions": 2, "deletions": 1, "is_test": false, "path": "adapters/netlify/tsconfig.json", "signals": ["path_token_overlap", "shared_config_or_schema"]}, {"additions": 1, "deletions": 1, "is_test": true, "path": "adapters/netlify/src/conninfo.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"adapters/netlify/src/conninfo.test.ts": ["adapters", "conninfo", "netlify"], "adapters/netlify/src/index.ts": ["index", "adapters", "netlify"], "adapters/netlify/src/mod.ts": ["adapters", "netlify"], "adapters/netlify/tsconfig.json": ["adapters", "netlify"]}}, "merged_at": "2026-09-28T08:38:04Z", "pr": 5468, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "shared_config_or_schema", "optional_test_ripple"], "source_pr": "https://github.com/honojs/hono/pull/5468"}, "query": {"anchor_diff": "@@ -38,7 +38,7 @@ type Env = {\n * @example\n * ```ts\n * import { Hono } from 'hono'\n- * import { handle, getConnInfo } from './index'\n+ * import { handle, getConnInfo } from '@hono/netlify'\n *\n * const app = new Hono()\n *", "anchor_file": "adapters/netlify/src/conninfo.ts", "intent": "feat(adapters/netlify): publish to JSR\n\n### The author should do the following, if applicable\n\n- [ ] Add tests\n- [ ] Run tests\n- [ ] `pnpm run check:fix` to format and lint the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code\n\nfeat(adapters/netlify): publish to JSR"}, "repo": "honojs/hono", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "e74a32413083a97bb7a96588708423be0c880227", "candidate_corpus": {"base_commit": "e74a32413083a97bb7a96588708423be0c880227", "type": "repo_at_base_commit"}, "gold": {"files": ["src/black/mode.py", "src/black/resources/black.schema.json", "src/black/lines.py"], "given_files": ["src/black/linegen.py"]}, "id": "43ec01b6ec355f1d02ac2c95", "metadata": {"changed_files": ["CHANGES.md", "docs/the_black_code_style/future_style.md", "src/black/linegen.py", "src/black/lines.py", "src/black/mode.py", "src/black/resources/black.schema.json", "tests/data/cases/preview_keep_commented_expressions_together.py"], "created_at": "2026-09-29T17:41:56Z", "fix_commit": "d9d091de04dd5872a308c8a60ca03b093c500e14", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 0, "is_test": false, "path": "src/black/mode.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 1, "deletions": 0, "is_test": false, "path": "src/black/resources/black.schema.json", "signals": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"]}, {"additions": 2, "deletions": 5, "is_test": false, "path": "src/black/lines.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"src/black/lines.py": ["lines", "black"], "src/black/mode.py": ["mode", "black"], "src/black/resources/black.schema.json": ["black"]}}, "merged_at": "2026-10-05T04:23:45Z", "pr": 5455, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"], "source_pr": "https://github.com/psf/black/pull/5455"}, "query": {"anchor_diff": "@@ -1611,6 +1611,22 @@ def delimiter_split(\n raise CannotSplit(\"Splitting a single attribute from its owner looks wrong\")\n \n rhs: RHSResult | None = None\n+ if (\n+ Preview.keep_commented_expressions_together in mode\n+ and line.contains_standalone_comments()\n+ and delimiter_priority != COMMA_PRIORITY\n+ ):\n+ first_comment_idx = next(\n+ i for i, leaf in enumerate(line.leaves) if leaf.type == STANDALONE_COMMENT\n+ )\n+ first_delimiter_idx = next(\n+ i\n+ for i, leaf in enumerate(line.leaves)\n+ if bt.delimiters.get(id(leaf)) == delimiter_priority\n+ )\n+ if first_comment_idx < first_delimiter_idx:\n+ raise CannotSplit(\"Standalone comments should be split first\")\n+\n if (\n Preview.hug_comparator in mode\n and delimiter_priority == COMPARATOR_PRIORITY", "anchor_file": "src/black/linegen.py", "intent": "Fix unnecessary line breaks for expressions with comments under preview (#4026, #3713)\n\n## Summary\n\nFixes #4026\nFixes #3713\n\n### Problem\n\nWhen a bracketed construct (such as a list literal or function call) contains a standalone comment\nbefore a short expression with operators (binary math, comparisons, comprehensions, etc.), Black\nunnecessarily breaks the expression across multiple lines even when it easily fits well within\n`--line-length`:\n\n```python\n# Before\nfoobar = [\n # comment\n pathlib.Path(\"foo\")\n / \"bar\"\n / \"baz\",\n]\n\nfizzbuzz = [\n # comment\n 23\n / 7\n]\n\nfunc(\n # comment\n a\n * b\n)\n```\n\n### Solution\n\nAvoid splitting on delimiters when a preceding standalone comment pushed the line onto its own line\nand the expression comfortably fits on a single line.\n\n```py\n# After (with --preview)\nfoobar = [\n # comment\n pathlib.Path(\"foo\") / \"bar\" / \"baz\",\n]\n\nfizzbuzz = [\n # comment\n 23 / 7\n]\n\nfunc(\n # comment\n a * b\n)\n```\n\n## Test Plan\n\n- Added regression tests in tests/data/cases/.\n- Ran full test suite and pre-commit checks.\n\nKeep commented expressions together in preview (#4026, #3713)\n\nMerge branch 'main' into fix-commented-binary-op-linebreak-4026"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "e74a32413083a97bb7a96588708423be0c880227", "candidate_corpus": {"base_commit": "e74a32413083a97bb7a96588708423be0c880227", "type": "repo_at_base_commit"}, "gold": {"files": ["src/black/linegen.py", "src/black/mode.py", "src/black/resources/black.schema.json"], "given_files": ["src/black/lines.py"]}, "id": "a50213d236f72f5ca8cd2250", "metadata": {"changed_files": ["CHANGES.md", "docs/the_black_code_style/future_style.md", "src/black/linegen.py", "src/black/lines.py", "src/black/mode.py", "src/black/resources/black.schema.json", "tests/data/cases/preview_keep_commented_expressions_together.py"], "created_at": "2026-09-29T17:41:56Z", "fix_commit": "d9d091de04dd5872a308c8a60ca03b093c500e14", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 16, "deletions": 0, "is_test": false, "path": "src/black/linegen.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 1, "deletions": 0, "is_test": false, "path": "src/black/mode.py", "signals": ["same_component", "path_token_overlap"]}, {"additions": 1, "deletions": 0, "is_test": false, "path": "src/black/resources/black.schema.json", "signals": ["path_token_overlap", "shared_config_or_schema"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"src/black/linegen.py": ["black"], "src/black/mode.py": ["black"], "src/black/resources/black.schema.json": ["black"]}}, "merged_at": "2026-10-05T04:23:45Z", "pr": 5455, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"], "source_pr": "https://github.com/psf/black/pull/5455"}, "query": {"anchor_diff": "@@ -100,8 +100,7 @@ class Line:\n # when its opening bracket was split onto an earlier line (for\n # example by a standalone comment inside the tuple), so verify\n # against the tree here before dropping the comma.\n- leaf.parent is not None\n- and is_one_tuple(leaf.parent)\n+ leaf.parent is not None and is_one_tuple(leaf.parent)\n ):\n self.remove_trailing_comma()\n if not self.append_comment(leaf):\n@@ -1708,9 +1707,7 @@ def can_omit_invisible_parens(\n or (\n # don't use indexing for omitting optional parentheses;\n # it looks weird\n- last.type == token.RSQB\n- and last.parent\n- and last.parent.type != syms.trailer\n+ last.type == token.RSQB and last.parent and last.parent.type != syms.trailer\n )\n ):\n if penultimate.type in OPENING_BRACKETS:", "anchor_file": "src/black/lines.py", "intent": "Fix unnecessary line breaks for expressions with comments under preview (#4026, #3713)\n\n## Summary\n\nFixes #4026\nFixes #3713\n\n### Problem\n\nWhen a bracketed construct (such as a list literal or function call) contains a standalone comment\nbefore a short expression with operators (binary math, comparisons, comprehensions, etc.), Black\nunnecessarily breaks the expression across multiple lines even when it easily fits well within\n`--line-length`:\n\n```python\n# Before\nfoobar = [\n # comment\n pathlib.Path(\"foo\")\n / \"bar\"\n / \"baz\",\n]\n\nfizzbuzz = [\n # comment\n 23\n / 7\n]\n\nfunc(\n # comment\n a\n * b\n)\n```\n\n### Solution\n\nAvoid splitting on delimiters when a preceding standalone comment pushed the line onto its own line\nand the expression comfortably fits on a single line.\n\n```py\n# After (with --preview)\nfoobar = [\n # comment\n pathlib.Path(\"foo\") / \"bar\" / \"baz\",\n]\n\nfizzbuzz = [\n # comment\n 23 / 7\n]\n\nfunc(\n # comment\n a * b\n)\n```\n\n## Test Plan\n\n- Added regression tests in tests/data/cases/.\n- Ran full test suite and pre-commit checks.\n\nKeep commented expressions together in preview (#4026, #3713)\n\nMerge branch 'main' into fix-commented-binary-op-linebreak-4026"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "f65a19b46a356e613d5f8642839f26d47c0dbc8d", "candidate_corpus": {"base_commit": "f65a19b46a356e613d5f8642839f26d47c0dbc8d", "type": "repo_at_base_commit"}, "gold": {"files": ["src/black/resources/black.schema.json", "src/black/linegen.py"], "given_files": ["src/black/mode.py"]}, "id": "416b48ababafefe3c4f0dc62", "metadata": {"changed_files": ["CHANGES.md", "docs/the_black_code_style/future_style.md", "src/black/linegen.py", "src/black/mode.py", "src/black/resources/black.schema.json", "tests/data/cases/preview_magic_trailing_comma_trailer_split.py"], "created_at": "2026-09-28T06:35:49Z", "fix_commit": "6aba61865bc1b35c605fb9989d9461036ae5bca9", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 0, "is_test": false, "path": "src/black/resources/black.schema.json", "signals": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"]}, {"additions": 16, "deletions": 0, "is_test": false, "path": "src/black/linegen.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"src/black/linegen.py": ["black"], "src/black/resources/black.schema.json": ["black"]}}, "merged_at": "2026-10-01T15:37:10Z", "pr": 5448, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema", "same_component"], "source_pr": "https://github.com/psf/black/pull/5448"}, "query": {"anchor_diff": "@@ -267,6 +267,7 @@ class Preview(Enum):\n remove_redundant_generator_parentheses = auto()\n normalize_tstring_prefix = auto()\n remove_redundant_unpacking_parentheses = auto()\n+ fix_magic_trailing_comma_trailer_split = auto()\n keep_dict_keys_with_operators = auto()", "anchor_file": "src/black/mode.py", "intent": "Split only the magic trailing comma's brackets when trailers follow\n\n### Description\n\nFixes #3268.\n\nWhen a magic trailing comma is followed by more trailers, Black also splits inside a later trailer:\n\n```python\nb = [1,][2](3)\n```\n\nbecomes\n\n```python\nb = [\n 1,\n][\n 2\n](3)\n```\n\n`right_hand_split_with_omits` tries omit sets from `generate_trailers_to_omit` and takes the first one whose head line fits. For this line the first candidate splits at `[2]`, and its head `b = [1,][` fits. That head still holds the magic trailing comma, so it explodes too, and the split inside `[2]` is wasted. `a = [1,][2]()` escapes the bug only because the empty `()` never produces an omit set of its own.\n\nUnder a new preview feature, `fix_magic_trailing_comma_trailer_split`, `right_hand_split_with_omits` skips a candidate whose head still has a magic trailing comma and moves on to the omit set that splits at the comma's own brackets. If no later candidate fits, it falls back to the first skipped one, so lines that only fit that way keep today's output. With the feature on, the example becomes:\n\n```python\nb = [\n 1,\n][2](3)\n```\n\nThe change sits behind `--preview` because it changes the output for code that Black has already formatted.\n\nVerification:\n\n- The new case `preview_magic_trailing_comma_trailer_split.py` fails on `main` (three of its five lines split inside `[2]`) and passes with the fix. It lands in its own commit before the fix.\n- The full test suite passes: 502 passed, 3 skipped.\n- `--preview` output is byte-identical before and after the change across 20,731 files from the `datasets`, `hermes-agent`, and `llama-index-core` sources. Stable output does not change.\n- pre-commit (isort, flake8, mypy, prettier) passes.\n\nAn AI agent (Claude Code) wrote this change and PR description\n...[truncated]"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "f65a19b46a356e613d5f8642839f26d47c0dbc8d", "candidate_corpus": {"base_commit": "f65a19b46a356e613d5f8642839f26d47c0dbc8d", "type": "repo_at_base_commit"}, "gold": {"files": ["src/black/mode.py", "src/black/resources/black.schema.json"], "given_files": ["src/black/linegen.py"]}, "id": "8bac90f53e8b43ee7d977817", "metadata": {"changed_files": ["CHANGES.md", "docs/the_black_code_style/future_style.md", "src/black/linegen.py", "src/black/mode.py", "src/black/resources/black.schema.json", "tests/data/cases/preview_magic_trailing_comma_trailer_split.py"], "created_at": "2026-09-28T06:35:49Z", "fix_commit": "6aba61865bc1b35c605fb9989d9461036ae5bca9", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 0, "is_test": false, "path": "src/black/mode.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 1, "deletions": 0, "is_test": false, "path": "src/black/resources/black.schema.json", "signals": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"src/black/mode.py": ["mode", "black"], "src/black/resources/black.schema.json": ["black"]}}, "merged_at": "2026-10-01T15:37:10Z", "pr": 5448, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"], "source_pr": "https://github.com/psf/black/pull/5448"}, "query": {"anchor_diff": "@@ -1021,6 +1021,7 @@ def right_hand_split_with_omits(\n content), meaning the trailers get glued together to split on another\n bracket pair instead.\n \"\"\"\n+ fallback_omit: set[LeafID] | None = None\n for omit in generate_trailers_to_omit(line, mode.line_length):\n lines = list(right_hand_split(line, mode, features, omit=omit))\n # Note: this check is only able to figure out if the first line of the\n@@ -1030,9 +1031,24 @@ def right_hand_split_with_omits(\n if is_line_short_enough(lines[0], mode=mode) or (\n omit and _over_length_only_due_to_subscript_comment(lines[0], mode)\n ):\n+ if (\n+ Preview.fix_magic_trailing_comma_trailer_split in mode\n+ and line.magic_trailing_comma\n+ and lines[0].magic_trailing_comma\n+ ):\n+ # The head still has to explode on its magic trailing comma, so\n+ # splitting this trailer too is wasted. Prefer a later omit that\n+ # splits on the magic trailing comma's own brackets.\n+ if fallback_omit is None:\n+ fallback_omit = set(omit)\n+ continue\n yield from lines\n return\n \n+ if fallback_omit is not None:\n+ yield from right_hand_split(line, mode, features, omit=fallback_omit)\n+ return\n+\n # All splits failed, best effort split with no omits.\n # This mostly happens to multiline strings that are by definition\n # reported as not fitting a single line, as well as lines that contain", "anchor_file": "src/black/linegen.py", "intent": "Split only the magic trailing comma's brackets when trailers follow\n\n### Description\n\nFixes #3268.\n\nWhen a magic trailing comma is followed by more trailers, Black also splits inside a later trailer:\n\n```python\nb = [1,][2](3)\n```\n\nbecomes\n\n```python\nb = [\n 1,\n][\n 2\n](3)\n```\n\n`right_hand_split_with_omits` tries omit sets from `generate_trailers_to_omit` and takes the first one whose head line fits. For this line the first candidate splits at `[2]`, and its head `b = [1,][` fits. That head still holds the magic trailing comma, so it explodes too, and the split inside `[2]` is wasted. `a = [1,][2]()` escapes the bug only because the empty `()` never produces an omit set of its own.\n\nUnder a new preview feature, `fix_magic_trailing_comma_trailer_split`, `right_hand_split_with_omits` skips a candidate whose head still has a magic trailing comma and moves on to the omit set that splits at the comma's own brackets. If no later candidate fits, it falls back to the first skipped one, so lines that only fit that way keep today's output. With the feature on, the example becomes:\n\n```python\nb = [\n 1,\n][2](3)\n```\n\nThe change sits behind `--preview` because it changes the output for code that Black has already formatted.\n\nVerification:\n\n- The new case `preview_magic_trailing_comma_trailer_split.py` fails on `main` (three of its five lines split inside `[2]`) and passes with the fix. It lands in its own commit before the fix.\n- The full test suite passes: 502 passed, 3 skipped.\n- `--preview` output is byte-identical before and after the change across 20,731 files from the `datasets`, `hermes-agent`, and `llama-index-core` sources. Stable output does not change.\n- pre-commit (isort, flake8, mypy, prettier) passes.\n\nAn AI agent (Claude Code) wrote this change and PR description\n...[truncated]"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "939fa93a1327d2a5f2829e6c1d7e4bd25a17b0f7", "candidate_corpus": {"base_commit": "939fa93a1327d2a5f2829e6c1d7e4bd25a17b0f7", "type": "repo_at_base_commit"}, "gold": {"files": ["src/black/mode.py", "src/black/resources/black.schema.json"], "given_files": ["src/black/linegen.py"]}, "id": "43ef4822b7ff2c671281bb6b", "metadata": {"changed_files": ["CHANGES.md", "docs/the_black_code_style/future_style.md", "src/black/linegen.py", "src/black/mode.py", "src/black/resources/black.schema.json", "tests/data/cases/preview_parenthesize_expressions_with_comments.py"], "created_at": "2026-09-27T13:52:56Z", "fix_commit": "eb8835829969f82c2567119f528b188769f3ac6d", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 0, "is_test": false, "path": "src/black/mode.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 2, "deletions": 1, "is_test": false, "path": "src/black/resources/black.schema.json", "signals": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"src/black/mode.py": ["mode", "black"], "src/black/resources/black.schema.json": ["black"]}}, "merged_at": "2026-10-07T17:22:14Z", "pr": 5442, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"], "source_pr": "https://github.com/psf/black/pull/5442"}, "query": {"anchor_diff": "@@ -2603,7 +2603,14 @@ def run_transformer(\n # `transform(line)` potentially destroys the line's underlying node\n # structure), then we can't proceed. Doing so would cause the below\n # call to `append_leaves()` to fail.\n- or any(leaf.parent is None for leaf in line.leaves)\n+ or any(\n+ leaf.parent is None\n+ for leaf in line.leaves\n+ if (\n+ Preview.parenthesize_expressions_with_comments not in mode\n+ or leaf.type != STANDALONE_COMMENT\n+ )\n+ )\n ):\n return result\n \n@@ -2613,6 +2620,13 @@ def run_transformer(\n second_opinion = run_transformer(\n line_copy, transform, mode, features_fop, line_str=line_str\n )\n- if all(is_line_short_enough(ln, mode=mode) for ln in second_opinion):\n+ if all(\n+ is_line_short_enough(ln, mode=mode)\n+ for ln in second_opinion\n+ if (\n+ Preview.parenthesize_expressions_with_comments not in mode\n+ or not ln.is_comment\n+ )\n+ ):\n result = second_opinion\n return result", "anchor_file": "src/black/linegen.py", "intent": "Parenthesize expressions with parameter comments in preview (#3113)\n\nParenthesize expressions with parameter comments when they exceed the line length under `--preview`.\n\nFixes #3113\n\n ## Summary of Changes\n\n- **Preview feature**: Added the `parenthesize_expressions_with_comments` preview option.\n- **Formatting logic**: Parenthesize assignment expressions containing parameter comments when the line exceeds the maximum line length.\n- **Documentation**: Added documentation and a reproducible example to `docs/the_black_code_style/future_style.md`.\n- **Changelog**: Added an entry under `Unreleased` preview style in `CHANGES.md`.\n- **Tests**: Added test cases in `tests/data/cases/preview_parenthesize_expressions_with_comments.py`.\n\nParenthesize expressions with parameter comments in preview (#3113) (#5442)\n\nAddress review comments on documentation example and line length\n\nMerge branch 'main' into fix-function-param-comments-wrap-3113"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "939fa93a1327d2a5f2829e6c1d7e4bd25a17b0f7", "candidate_corpus": {"base_commit": "939fa93a1327d2a5f2829e6c1d7e4bd25a17b0f7", "type": "repo_at_base_commit"}, "gold": {"files": ["src/black/resources/black.schema.json", "src/black/linegen.py"], "given_files": ["src/black/mode.py"]}, "id": "c75ff3829dbba17a5126d62a", "metadata": {"changed_files": ["CHANGES.md", "docs/the_black_code_style/future_style.md", "src/black/linegen.py", "src/black/mode.py", "src/black/resources/black.schema.json", "tests/data/cases/preview_parenthesize_expressions_with_comments.py"], "created_at": "2026-09-27T13:52:56Z", "fix_commit": "eb8835829969f82c2567119f528b188769f3ac6d", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 2, "deletions": 1, "is_test": false, "path": "src/black/resources/black.schema.json", "signals": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"]}, {"additions": 16, "deletions": 2, "is_test": false, "path": "src/black/linegen.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"src/black/linegen.py": ["black"], "src/black/resources/black.schema.json": ["black"]}}, "merged_at": "2026-10-07T17:22:14Z", "pr": 5442, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema", "same_component"], "source_pr": "https://github.com/psf/black/pull/5442"}, "query": {"anchor_diff": "@@ -272,6 +272,7 @@ class Preview(Enum):\n blank_line_after_stub_method = auto()\n keep_commented_expressions_together = auto()\n avoid_parens_for_unbreakable_rhs_in_assignments = auto()\n+ parenthesize_expressions_with_comments = auto()\n \n \n UNSTABLE_FEATURES: set[Preview] = {", "anchor_file": "src/black/mode.py", "intent": "Parenthesize expressions with parameter comments in preview (#3113)\n\nParenthesize expressions with parameter comments when they exceed the line length under `--preview`.\n\nFixes #3113\n\n ## Summary of Changes\n\n- **Preview feature**: Added the `parenthesize_expressions_with_comments` preview option.\n- **Formatting logic**: Parenthesize assignment expressions containing parameter comments when the line exceeds the maximum line length.\n- **Documentation**: Added documentation and a reproducible example to `docs/the_black_code_style/future_style.md`.\n- **Changelog**: Added an entry under `Unreleased` preview style in `CHANGES.md`.\n- **Tests**: Added test cases in `tests/data/cases/preview_parenthesize_expressions_with_comments.py`.\n\nParenthesize expressions with parameter comments in preview (#3113) (#5442)\n\nAddress review comments on documentation example and line length\n\nMerge branch 'main' into fix-function-param-comments-wrap-3113"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "994ef7eeb18172178552daa1f36f001d156ad583", "candidate_corpus": {"base_commit": "994ef7eeb18172178552daa1f36f001d156ad583", "type": "repo_at_base_commit"}, "gold": {"files": ["src/black/mode.py", "src/black/resources/black.schema.json"], "given_files": ["src/black/lines.py"]}, "id": "2eb85b660e3a6cfdc400f9a9", "metadata": {"changed_files": ["CHANGES.md", "docs/the_black_code_style/future_style.md", "src/black/lines.py", "src/black/mode.py", "src/black/resources/black.schema.json", "tests/data/cases/blank_line_after_stub_method.py"], "created_at": "2026-09-26T22:52:16Z", "fix_commit": "5fe7881e6e40ceeed3c9e3212cbc70a040adea28", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 0, "is_test": false, "path": "src/black/mode.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 2, "deletions": 1, "is_test": false, "path": "src/black/resources/black.schema.json", "signals": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"src/black/mode.py": ["mode", "black"], "src/black/resources/black.schema.json": ["black", "json", "schema"]}}, "merged_at": "2026-10-03T18:51:19Z", "pr": 5439, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"], "source_pr": "https://github.com/psf/black/pull/5439"}, "query": {"anchor_diff": "@@ -1311,7 +1311,14 @@ class EmptyLineTracker:\n newlines = 1 if current_line.depth else 2\n # If a user has left no space after a dummy implementation, don't insert\n # new lines. This is useful for instance for @overload or Protocols.\n- if self.previous_line.is_stub_def and not user_had_newline:\n+ if (\n+ self.previous_line.is_stub_def\n+ and not user_had_newline\n+ and (\n+ Preview.blank_line_after_stub_method not in self.mode\n+ or self.previous_line.depth == current_line.depth\n+ )\n+ ):\n newlines = 0\n if comment_to_add_newlines is not None:\n previous_block = comment_to_add_newlines.previous_block", "anchor_file": "src/black/lines.py", "intent": "Fix preview blank lines after a stub method\n\nFixes #4420.\n\nWhen the last method in a class has an ellipsis body, Black currently treats the next class or function as another adjacent stub and suppresses the blank lines between them. In preview mode, keep that compact formatting only for stub definitions at the same indentation level.\n\nThe regression case covers top-level classes, a decorated class, a following function, nested classes, and consecutive stub methods. It fails before the change. The generated JSON schema includes the new preview feature. On Python 3.14.7, `tox -e py` passes both phases: 504 passed and 1 skipped without Jupyter, followed by 75 passed with Jupyter (`NO_COLOR` unset). All pre-commit checks and `tox -e run_self` pass. Re-running `tox -e generate_schema` leaves the generated schema unchanged.\n\nImplemented with OpenAI Codex assistance.\n\nFix preview blank lines after a stub method\n\n[pre-commit.ci] auto fixes from pre-commit.com hooks\n\nRegenerate schema for stub method preview feature\n\nMerge main and preserve all preview schema features"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "994ef7eeb18172178552daa1f36f001d156ad583", "candidate_corpus": {"base_commit": "994ef7eeb18172178552daa1f36f001d156ad583", "type": "repo_at_base_commit"}, "gold": {"files": ["src/black/resources/black.schema.json", "src/black/lines.py"], "given_files": ["src/black/mode.py"]}, "id": "895f6b36de64d9fbc2a85a49", "metadata": {"changed_files": ["CHANGES.md", "docs/the_black_code_style/future_style.md", "src/black/lines.py", "src/black/mode.py", "src/black/resources/black.schema.json", "tests/data/cases/blank_line_after_stub_method.py"], "created_at": "2026-09-26T22:52:16Z", "fix_commit": "5fe7881e6e40ceeed3c9e3212cbc70a040adea28", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 2, "deletions": 1, "is_test": false, "path": "src/black/resources/black.schema.json", "signals": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"]}, {"additions": 8, "deletions": 1, "is_test": false, "path": "src/black/lines.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"src/black/lines.py": ["lines", "black"], "src/black/resources/black.schema.json": ["black", "json", "schema"]}}, "merged_at": "2026-10-03T18:51:19Z", "pr": 5439, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema", "same_component"], "source_pr": "https://github.com/psf/black/pull/5439"}, "query": {"anchor_diff": "@@ -269,6 +269,7 @@ class Preview(Enum):\n remove_redundant_unpacking_parentheses = auto()\n fix_magic_trailing_comma_trailer_split = auto()\n keep_dict_keys_with_operators = auto()\n+ blank_line_after_stub_method = auto()\n \n \n UNSTABLE_FEATURES: set[Preview] = {", "anchor_file": "src/black/mode.py", "intent": "Fix preview blank lines after a stub method\n\nFixes #4420.\n\nWhen the last method in a class has an ellipsis body, Black currently treats the next class or function as another adjacent stub and suppresses the blank lines between them. In preview mode, keep that compact formatting only for stub definitions at the same indentation level.\n\nThe regression case covers top-level classes, a decorated class, a following function, nested classes, and consecutive stub methods. It fails before the change. The generated JSON schema includes the new preview feature. On Python 3.14.7, `tox -e py` passes both phases: 504 passed and 1 skipped without Jupyter, followed by 75 passed with Jupyter (`NO_COLOR` unset). All pre-commit checks and `tox -e run_self` pass. Re-running `tox -e generate_schema` leaves the generated schema unchanged.\n\nImplemented with OpenAI Codex assistance.\n\nFix preview blank lines after a stub method\n\n[pre-commit.ci] auto fixes from pre-commit.com hooks\n\nRegenerate schema for stub method preview feature\n\nMerge main and preserve all preview schema features"}, "repo": "psf/black", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "2772c28f7a8304edec67a9eface937841cee1f74", "candidate_corpus": {"base_commit": "2772c28f7a8304edec67a9eface937841cee1f74", "type": "repo_at_base_commit"}, "gold": {"files": ["runtime-tests/workerd/index.ts", "src/middleware/logger/index.ts", "src/utils/color.test.ts", "runtime-tests/workerd/index.test.ts"], "given_files": ["src/utils/color.ts"]}, "id": "8082e4b966ac66c8cfd775a2", "metadata": {"changed_files": ["docs/MIGRATION.md", "runtime-tests/workerd/index.test.ts", "runtime-tests/workerd/index.ts", "src/middleware/logger/index.test.ts", "src/middleware/logger/index.ts", "src/utils/color.test.ts", "src/utils/color.ts"], "created_at": "2026-09-15T19:06:19Z", "fix_commit": "e92826579e5da60671a01d73f0ad2bf32a834be8", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 15, "deletions": 4, "is_test": false, "path": "runtime-tests/workerd/index.ts", "signals": ["gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 6, "deletions": 20, "is_test": false, "path": "src/middleware/logger/index.ts", "signals": ["gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 41, "deletions": 7, "is_test": true, "path": "src/utils/color.test.ts", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 17, "deletions": 0, "is_test": true, "path": "runtime-tests/workerd/index.test.ts", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"runtime-tests/workerd/index.test.ts": ["runtime"], "runtime-tests/workerd/index.ts": ["runtime"], "src/middleware/logger/index.ts": ["logger", "middleware"], "src/utils/color.test.ts": ["color"]}}, "merged_at": "2026-10-07T06:31:50Z", "pr": 5402, "ripple_relation": ["gold_diff_mentions_anchor_module", "shared_changed_symbol", "path_token_overlap", "optional_test_ripple"], "source_pr": "https://github.com/honojs/hono/pull/5402"}, "query": {"anchor_diff": "@@ -5,52 +5,25 @@\n \n /**\n * Get whether color change on terminal is enabled or disabled.\n- * If `NO_COLOR` environment variable is set, this function returns `false`.\n- * Unlike getColorEnabledAsync(), this cannot check Cloudflare environment variables.\n+ * If `NO_COLOR` is set in the provided bindings or runtime environment, this function returns `false`.\n+ * Pass Cloudflare Workers bindings explicitly, for example `getColorEnabled(c.env)`.\n * @see {@link https://no-color.org/}\n *\n+ * @param {object} [env] - Optional environment bindings to check in addition to the runtime environment.\n * @returns {boolean}\n */\n-export function getColorEnabled(): boolean {\n+export function getColorEnabled(env?: object): boolean {\n+ if (env && 'NO_COLOR' in env) {\n+ return false\n+ }\n+\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const { process, Deno } = globalThis as any\n \n const isNoColor =\n typeof Deno?.noColor === 'boolean'\n ? (Deno.noColor as boolean)\n- : process !== undefined\n- ? // eslint-disable-next-line no-unsafe-optional-chaining\n- 'NO_COLOR' in process?.env\n- : false\n-\n- return !isNoColor\n-}\n-\n-/**\n- * Get whether color change on terminal is enabled or disabled.\n- * If `NO_COLOR` environment variable is set, this function returns `false`.\n- * @see {@link https://no-color.org/}\n- *\n- * @returns {boolean}\n- */\n-export async function getColorEnabledAsync(): Promise {\n- // eslint-disable-next-line @typescript-eslint/no-explicit-any\n- const { navigator } = globalThis as any\n- // Avoid analysis of cloudflare scheme by bundlers\n- const cfWorkers = 'cloudflare:workers'\n-\n- const isNoColor =\n- navigator !== undefined && navigator.userAgent === 'Cloudflare-Workers'\n- ? await (async () => {\n- try {\n- // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n- // @ts-ignore\n- return 'NO_COLOR' in ((await import(cfWorkers)).env ?? {}) // {} is for backward compat\n- } catch {\n- return false\n- }\n- })()\n- : !getColorEnabled()\n+ : 'NO_COLOR' in (process?.env ?? {})\n \n return !isNoColor\n }", "anchor_file": "src/utils/color.ts", "intent": "refactor(logger)!: make color detection synchronous for v5\n\nThe logger currently awaits color detection on every outgoing log line, including a dynamic `cloudflare:workers` import on Workers. Pass `c.env` to `getColorEnabled(env?)` so color detection and formatting are synchronous and the middleware only awaits `next()`.\n\nCheck bindings on each call, then fall back to the existing Deno/process detection. Remove the async helper and the import workarounds; the two production files shrink by 41 lines.\n\n**Breaking change for v5:** remove `getColorEnabledAsync()` from `hono/utils/color`. Callers should use `getColorEnabled()`, passing `c.env` or Worker bindings explicitly on Cloudflare. Includes a migration note.\n\nRelated to #5106. Draft against `main` because there is no v5 branch yet.\n\n### Validation\n\n- `env -u NO_COLOR bun run test`: 5,161 passed, 44 skipped, including Workers tests with `disallow_importable_env`.\n- `env -u NO_COLOR bun run test:bun`: 26 passed.\n- Deno smoke check for color detection and logger bindings.\n- Build, formatting, lint, and EditorConfig checks passed. Lint and package validation report existing warnings outside the changed files.\n\n`NO_COLOR` was unset for test commands because the local shell sets it to `1`; the tests cover it explicitly.\n\n### The author should do the following, if applicable\n\n- [x] Add tests\n- [x] Run tests\n- [x] Format and lint the code\n- [x] Add JSDoc to document the code\n\nfix(cors): append Origin to Vary header on OPTIONS preflight (#5235)\n\ndocs(context): add custom headers append option example to Context JSDoc (#5248)\n\nfix(trie-router): match suffix wildcard routes (#5236)\n\nfix(pattern-router/linear-router): prevent prefix overmatch on wildcard routes (#5252)\n\nfix(csrf): exempt OPTIONS request from CSRF validation (#5250\n...[truncated]"}, "repo": "honojs/hono", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "eebdf7be39abf0a872671835ccce0c4f03ea497a", "candidate_corpus": {"base_commit": "eebdf7be39abf0a872671835ccce0c4f03ea497a", "type": "repo_at_base_commit"}, "gold": {"files": ["src/helper/route/index.ts"], "given_files": ["src/context.ts"]}, "id": "9e4192ab100014acd7dfd6a1", "metadata": {"changed_files": ["README.md", "src/context.ts", "src/helper/cookie/index.test.ts", "src/helper/proxy/index.ts", "src/helper/route/index.ts", "src/utils/types.ts"], "created_at": "2026-09-06T15:15:40Z", "fix_commit": "e7b38ee42bfa41f20194ad20fb949b625346be62", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 3, "deletions": 3, "is_test": false, "path": "src/helper/route/index.ts", "signals": ["gold_diff_mentions_anchor_module"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": [], "nonfatal_hits": {}}, "merged_at": "2026-09-08T09:59:09Z", "pr": 5343, "ripple_relation": ["gold_diff_mentions_anchor_module"], "source_pr": "https://github.com/honojs/hono/pull/5343"}, "query": {"anchor_diff": "@@ -771,7 +771,7 @@ export class Context<\n const locationString = String(location)\n this.header(\n 'Location',\n- // Multibyes should be encoded\n+ // Multibytes should be encoded\n // eslint-disable-next-line no-control-regex\n !/[^\\x00-\\xFF]/.test(locationString) ? locationString : encodeURI(locationString)\n )", "anchor_file": "src/context.ts", "intent": "docs: fix typos in code comments and link third-party middleware section\n\n### The author should do the following, if applicable\n\n- [ ] Add tests\n- [X] Run tests\n- [X] `bun run format:fix && bun run lint:fix` to format the code\n- [ ] Add [TSDoc](https://tsdoc.org/)/[JSDoc](https://jsdoc.app/about-getting-started) to document the code\n\ndocs: fix typos in code comments and link third-party middleware section"}, "repo": "honojs/hono", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "19c67b9a3479841e9133bea94607c89ee931d3fc", "candidate_corpus": {"base_commit": "19c67b9a3479841e9133bea94607c89ee931d3fc", "type": "repo_at_base_commit"}, "gold": {"files": ["tests/test_markdown.py"], "given_files": ["rich/markdown.py"]}, "id": "2c71c337dc4c43c55b6c3df1", "metadata": {"changed_files": ["CHANGELOG.md", "rich/markdown.py", "tests/test_markdown.py"], "created_at": "2026-04-12T07:40:33Z", "fix_commit": "ffe2edc5968eac19d5493c2d7b27965031a692e9", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 16, "deletions": 0, "is_test": true, "path": "tests/test_markdown.py", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"tests/test_markdown.py": ["markdown"]}}, "merged_at": "2026-04-12T07:45:03Z", "pr": 4079, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "optional_test_ripple"], "source_pr": "https://github.com/Textualize/rich/pull/4079"}, "query": {"anchor_diff": "@@ -331,9 +331,10 @@ class TableDataElement(MarkdownElement):\n self.justify = justify\n \n def on_text(self, context: MarkdownContext, text: TextType) -> None:\n- text = Text(text) if isinstance(text, str) else text\n- text.stylize(context.current_style)\n- self.content.append_text(text)\n+ if isinstance(text, str):\n+ self.content.append(text, context.current_style)\n+ else:\n+ self.content.append_text(text)\n \n \n class ListElement(MarkdownElement):", "anchor_file": "rich/markdown.py", "intent": "Inline table code\n\nFixes https://github.com/Textualize/rich/issues/4038\n\nfix inline code in table cells\n\nremove comments\n\nchangelog"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "58ac15120fe254886c10d6253667733c83604cb4", "candidate_corpus": {"base_commit": "58ac15120fe254886c10d6253667733c83604cb4", "type": "repo_at_base_commit"}, "gold": {"files": ["tests/test_file_proxy.py"], "given_files": ["rich/file_proxy.py"]}, "id": "3fba64a25078a8ca4f8415fa", "metadata": {"changed_files": ["CHANGELOG.md", "rich/file_proxy.py", "tests/test_file_proxy.py"], "created_at": "2026-04-12T04:06:31Z", "fix_commit": "19c67b9a3479841e9133bea94607c89ee931d3fc", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 17, "deletions": 0, "is_test": true, "path": "tests/test_file_proxy.py", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"tests/test_file_proxy.py": ["proxy"]}}, "merged_at": "2026-04-12T04:11:19Z", "pr": 4077, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/Textualize/rich/pull/4077"}, "query": {"anchor_diff": "@@ -55,3 +55,6 @@ class FileProxy(io.TextIOBase):\n \n def fileno(self) -> int:\n return self.__file.fileno()\n+\n+ def isatty(self) -> bool:\n+ return self.__file.isatty()", "anchor_file": "rich/file_proxy.py", "intent": "proxy isatty\n\nFixes https://github.com/Textualize/rich/issues/4041\n\nproxy isatty\n\nchangelog"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "9cb198944f8184df92217efc8b20d3fffa4b4fa0", "candidate_corpus": {"base_commit": "9cb198944f8184df92217efc8b20d3fffa4b4fa0", "type": "repo_at_base_commit"}, "gold": {"files": ["tests/test_ansi.py"], "given_files": ["rich/ansi.py"]}, "id": "80850b4764da8c9638dc5c5a", "metadata": {"changed_files": ["CHANGELOG.md", "docs/source/console.rst", "rich/ansi.py", "tests/test_ansi.py"], "created_at": "2026-04-11T10:33:23Z", "fix_commit": "58ac15120fe254886c10d6253667733c83604cb4", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 23, "deletions": 3, "is_test": true, "path": "tests/test_ansi.py", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"tests/test_ansi.py": ["ansi"]}}, "merged_at": "2026-04-12T03:59:42Z", "pr": 4076, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/Textualize/rich/pull/4076"}, "query": {"anchor_diff": "@@ -127,13 +127,13 @@ class AnsiDecoder:\n \"\"\"Decode ANSI codes in an iterable of lines.\n \n Args:\n- lines (Iterable[str]): An iterable of lines of terminal output.\n+ terminal_text: Output potentially containing ANSI escape sequences.\n \n Yields:\n Text: Marked up Text.\n \"\"\"\n- for line in terminal_text.splitlines():\n- yield self.decode_line(line)\n+ for line in re.split(r\"(?<=\\n)\", terminal_text):\n+ yield self.decode_line(line.rstrip(\"\\n\"))\n \n def decode_line(self, line: str) -> Text:\n \"\"\"Decode a line containing ansi codes.", "anchor_file": "rich/ansi.py", "intent": "preserve newlines\n\nFixes https://github.com/Textualize/rich/issues/3577\n\npreserve newlines\n\ntest\n\nchangelog\n\nremove old warning\n\ntest fixes\n\ntests\n\nws\n\nfix tests"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "7323a7514f7601737640e7172be115127d6db08c", "candidate_corpus": {"base_commit": "7323a7514f7601737640e7172be115127d6db08c", "type": "repo_at_base_commit"}, "gold": {"files": ["tests/integration_tests.rs"], "given_files": ["src/vscreen.rs"]}, "id": "43b6027f2b64f3e7d273e352", "metadata": {"changed_files": ["CHANGELOG.md", "src/vscreen.rs", "tests/integration_tests.rs"], "created_at": "2026-09-22T11:56:08Z", "fix_commit": "4987f76709aae3a1c4db723c53874c9ddcb0c4fd", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 19, "deletions": 0, "is_test": true, "path": "tests/integration_tests.rs", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"tests/integration_tests.rs": ["integration"]}}, "merged_at": "2026-09-22T18:13:31Z", "pr": 4015, "ripple_relation": ["shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/sharkdp/bat/pull/4015"}, "query": {"anchor_diff": "@@ -173,8 +173,10 @@ impl Attributes {\n 2 => self.dim = \"\\x1B[2m\".to_owned(),\n 3 => self.italic = \"\\x1B[3m\".to_owned(),\n 4 => self.underline = \"\\x1B[4m\".to_owned(),\n+ 9 => self.strike = \"\\x1B[9m\".to_owned(),\n 23 => self.italic.clear(),\n 24 => self.underline.clear(),\n+ 29 => self.strike.clear(),\n 22 => {\n self.bold.clear();\n self.dim.clear();\n@@ -1112,10 +1114,10 @@ mod tests {\n fn test_sgr_attributes_do_not_leak_into_wrong_field() {\n let mut attrs = crate::vscreen::Attributes::new();\n \n- // Bold, Dim, Italic, Underline, Foreground, Background\n+ // Bold, Dim, Italic, Underline, Strike, Foreground, Background\n attrs.update(EscapeSequence::CSI {\n- raw_sequence: \"\\x1B[1;2;3;4;31;41m\",\n- parameters: \"1;2;3;4;31;41\",\n+ raw_sequence: \"\\x1B[1;2;3;4;9;31;41m\",\n+ parameters: \"1;2;3;4;9;31;41\",\n intermediates: \"\",\n final_byte: \"m\",\n });\n@@ -1124,6 +1126,7 @@ mod tests {\n assert_eq!(attrs.dim, \"\\x1B[2m\");\n assert_eq!(attrs.italic, \"\\x1B[3m\");\n assert_eq!(attrs.underline, \"\\x1B[4m\");\n+ assert_eq!(attrs.strike, \"\\x1B[9m\");\n assert_eq!(attrs.foreground, \"\\x1B[31m\");\n assert_eq!(attrs.background, \"\\x1B[41m\");\n \n@@ -1140,4 +1143,27 @@ mod tests {\n assert_eq!(attrs.foreground, \"\\x1B[94m\");\n assert_eq!(attrs.background, \"\\x1B[103m\");\n }\n+\n+ #[test]\n+ fn test_sgr_strike_is_tracked_and_cleared() {\n+ let mut attrs = crate::vscreen::Attributes::new();\n+\n+ // Strikethrough on (SGR 9) must be tracked so it can be re-emitted.\n+ attrs.update(EscapeSequence::CSI {\n+ raw_sequence: \"\\x1B[9m\",\n+ parameters: \"9\",\n+ intermediates: \"\",\n+ final_byte: \"m\",\n+ });\n+ assert_eq!(attrs.strike, \"\\x1B[9m\");\n+\n+ // Strikethrough off (SGR 29) must clear it, just like italic (23) and underline (24).\n+ attrs.update(EscapeSequence::CSI {\n+ raw_sequence: \"\\x1B[29m\",\n+ parameters: \"29\",\n+ intermediates: \"\",\n+ final_byte: \"m\",\n+ });\n+ assert_eq!(attrs.strike, \"\");\n+ }\n }", "anchor_file": "src/vscreen.rs", "intent": "Track strikethrough (SGR 9) so it is not dropped across highlighted tokens\n\n## Summary\n\n`src/vscreen.rs` tracks the terminal's active ANSI style in an `Attributes` struct so bat can re-apply it before each syntax-highlighted token (nu_ansi_term appends a full `\\x1B[0m` reset after every token). The struct already has a `strike` field, documented `ON: ^[9m / OFF: ^[29m`, that is initialized, cleared in `sgr_reset()`, and re-emitted in `Display` — but `update_with_sgr()` had **no match arm for SGR `9` or `29`**, so `strike` was only ever cleared, never set.\n\nConsequence: with ANSI passthrough (the default — `--strip-ansi` and `--sanitize` both default to `never`), bold/dim/italic/underline survive across highlighted tokens because they are tracked and re-emitted, but strikethrough visibly disappears after the first token.\n\nThis adds the missing `9` (set) and `29` (clear) arms, mirroring the sibling underline (`4`/`24`) and italic (`3`/`23`) arms, so strikethrough persists like every other supported attribute. Two-line behavioral change; no API change. `to_reset_sequence()` intentionally does not reset SGR attributes yet (existing commented-out TODO), so `strike` is handled there exactly like bold/italic — no change needed.\n\n## Test Plan\n\n- `cargo test` (unit + integration).\n- Extended the `test_sgr_attributes_do_not_leak_into_wrong_field` unit test to include SGR `9`, and added `test_sgr_strike_is_tracked_and_cleared` covering set (`9`) and clear (`29`).\n- Added integration test `ansi_sgr_strike_joins_attributes_when_wrapped`, modeled on the existing `ansi_sgr_joins_attributes_when_wrapped`, asserting strikethrough is re-emitted across a wrap boundary. It fails before the fix and passes after.\n\nDeveloped with assistance from Claude Code; reviewed & validated by me.\n\n🤖 Gen\n...[truncated]"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "1d402e0c59f8765e420a5a4440eb2fca7465d1ae", "candidate_corpus": {"base_commit": "1d402e0c59f8765e420a5a4440eb2fca7465d1ae", "type": "repo_at_base_commit"}, "gold": {"files": ["tests/test_cells.py"], "given_files": ["rich/cells.py"]}, "id": "9293f517d75d489166ef4e44", "metadata": {"changed_files": ["CHANGELOG.md", "pyproject.toml", "rich/cells.py", "tests/test_cells.py"], "created_at": "2026-02-01T15:01:14Z", "fix_commit": "0752ff047295131d98f24284e1d949300cd6f4c1", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 17, "deletions": 0, "is_test": true, "path": "tests/test_cells.py", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"tests/test_cells.py": ["cells"]}}, "merged_at": "2026-02-01T16:19:21Z", "pr": 3953, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/Textualize/rich/pull/3953"}, "query": {"anchor_diff": "@@ -55,23 +55,26 @@ def get_character_cell_size(character: str, unicode_version: str = \"auto\") -> in\n int: Number of cells (0, 1 or 2) occupied by that character.\n \"\"\"\n codepoint = ord(character)\n+ if codepoint and codepoint < 32 or 0x07F <= codepoint < 0x0A0:\n+ return 0\n table = load_cell_table(unicode_version).widths\n- if codepoint > table[-1][1]:\n+\n+ last_entry = table[-1]\n+ if codepoint > last_entry[1]:\n return 1\n+\n lower_bound = 0\n upper_bound = len(table) - 1\n- index = (lower_bound + upper_bound) // 2\n- while True:\n+\n+ while lower_bound <= upper_bound:\n+ index = (lower_bound + upper_bound) >> 1\n start, end, width = table[index]\n if codepoint < start:\n upper_bound = index - 1\n elif codepoint > end:\n lower_bound = index + 1\n else:\n- return 0 if width == -1 else width\n- if upper_bound < lower_bound:\n- break\n- index = (lower_bound + upper_bound) // 2\n+ return width\n return 1\n \n \n@@ -135,12 +138,14 @@ def _cell_len(text: str, unicode_version: str) -> int:\n \n SPECIAL = {\"\\u200d\", \"\\ufe0f\"}\n \n- iter_characters = iter(text)\n+ index = 0\n+ character_count = len(text)\n \n- for character in iter_characters:\n+ while index < character_count:\n+ character = text[index]\n if character in SPECIAL:\n if character == \"\\u200d\":\n- next(iter_characters)\n+ index += 1\n elif last_measured_character:\n total_width += last_measured_character in cell_table.narrow_to_wide\n last_measured_character = None\n@@ -148,6 +153,7 @@ def _cell_len(text: str, unicode_version: str) -> int:\n if character_width := get_character_cell_size(character, unicode_version):\n last_measured_character = character\n total_width += character_width\n+ index += 1\n \n return total_width", "anchor_file": "rich/cells.py", "intent": "Fix ZWJ and edge cases\n\nFixes https://github.com/Textualize/rich/issues/3947\nFixes https://github.com/Textualize/rich/issues/3950\n\nFix ZWJ and edge cases\n\nstupid comment\n\nfix test\n\nrefine\n\nsimplify"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "36fe3f7ca9becca4777861d5e6e625f5a4a37545", "candidate_corpus": {"base_commit": "36fe3f7ca9becca4777861d5e6e625f5a4a37545", "type": "repo_at_base_commit"}, "gold": {"files": ["tests/test_cells.py"], "given_files": ["rich/cells.py"]}, "id": "af69dc21f14670eedb93035f", "metadata": {"changed_files": ["CHANGELOG.md", "pyproject.toml", "rich/cells.py", "tests/test_cells.py"], "created_at": "2026-01-24T21:33:50Z", "fix_commit": "f2a1c3b8a8f7edc41b1954cc3fb66bae32293a5e", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 6, "deletions": 0, "is_test": true, "path": "tests/test_cells.py", "signals": ["path_token_overlap", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"tests/test_cells.py": ["cells"]}}, "merged_at": "2026-01-24T21:40:01Z", "pr": 3944, "ripple_relation": ["path_token_overlap", "optional_test_ripple"], "source_pr": "https://github.com/Textualize/rich/pull/3944"}, "query": {"anchor_diff": "@@ -57,7 +57,7 @@ def get_character_cell_size(character: str, unicode_version: str = \"auto\") -> in\n codepoint = ord(character)\n table = load_cell_table(unicode_version).widths\n if codepoint > table[-1][1]:\n- return 0\n+ return 1\n lower_bound = 0\n upper_bound = len(table) - 1\n index = (lower_bound + upper_bound) // 2", "anchor_file": "rich/cells.py", "intent": "fix fonts\n\nFixes https://github.com/Textualize/rich/issues/3943\n\nfix fonts\n\nchangelog"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "05ff970926cbd0b5d0acb6fc18cdbd1fc971e582", "candidate_corpus": {"base_commit": "05ff970926cbd0b5d0acb6fc18cdbd1fc971e582", "type": "repo_at_base_commit"}, "gold": {"files": ["rich/segment.py", "tests/test_text.py", "tests/test_segment.py"], "given_files": ["rich/console.py"]}, "id": "297e3e869edc4da29ae2292a", "metadata": {"changed_files": ["CHANGELOG.md", "rich/console.py", "rich/segment.py", "tests/test_segment.py", "tests/test_text.py"], "created_at": "2026-01-23T15:04:54Z", "fix_commit": "3286095ff8b70e093dbbc4136ff7ba7d51944bec", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 31, "deletions": 0, "is_test": false, "path": "rich/segment.py", "signals": ["same_component", "path_token_overlap", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}, {"additions": 17, "deletions": 0, "is_test": true, "path": "tests/test_text.py", "signals": ["gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 15, "deletions": 0, "is_test": true, "path": "tests/test_segment.py", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"rich/segment.py": ["segment", "rich"], "tests/test_segment.py": ["segment"], "tests/test_text.py": ["text"]}}, "merged_at": "2026-01-23T15:33:08Z", "pr": 3938, "ripple_relation": ["same_component", "path_token_overlap", "anchor_diff_mentions_gold_module", "shared_changed_symbol", "gold_diff_mentions_anchor_module", "optional_test_ripple"], "source_pr": "https://github.com/Textualize/rich/pull/3938"}, "query": {"anchor_diff": "@@ -1723,12 +1723,16 @@ class Console:\n for renderable in renderables:\n extend(render(renderable, render_options))\n else:\n+ render_style = self.get_style(style)\n+ new_line = Segment.line()\n for renderable in renderables:\n- extend(\n- Segment.apply_style(\n- render(renderable, render_options), self.get_style(style)\n- )\n- )\n+ for line, add_new_line in Segment.split_lines_terminator(\n+ render(renderable, render_options)\n+ ):\n+ extend(Segment.apply_style(line, render_style))\n+ if add_new_line:\n+ new_segments.append(new_line)\n+\n if new_line_start:\n if (\n len(\"\".join(segment.text for segment in new_segments).splitlines())", "anchor_file": "rich/console.py", "intent": "fix background style with soft wrap\n\nFixes https://github.com/Textualize/rich/issues/3838\n\nfix background style with soft wrap\n\nchangelog\n\nsplit lines terminator\n\ntest"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "05ff970926cbd0b5d0acb6fc18cdbd1fc971e582", "candidate_corpus": {"base_commit": "05ff970926cbd0b5d0acb6fc18cdbd1fc971e582", "type": "repo_at_base_commit"}, "gold": {"files": ["rich/console.py", "tests/test_segment.py", "tests/test_text.py"], "given_files": ["rich/segment.py"]}, "id": "ff60d0602795b700390b9328", "metadata": {"changed_files": ["CHANGELOG.md", "rich/console.py", "rich/segment.py", "tests/test_segment.py", "tests/test_text.py"], "created_at": "2026-01-23T15:04:54Z", "fix_commit": "3286095ff8b70e093dbbc4136ff7ba7d51944bec", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 9, "deletions": 5, "is_test": false, "path": "rich/console.py", "signals": ["same_component", "path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 15, "deletions": 0, "is_test": true, "path": "tests/test_segment.py", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 17, "deletions": 0, "is_test": true, "path": "tests/test_text.py", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"rich/console.py": ["rich"], "tests/test_segment.py": ["segment"], "tests/test_text.py": ["text"]}}, "merged_at": "2026-01-23T15:33:08Z", "pr": 3938, "ripple_relation": ["same_component", "path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/Textualize/rich/pull/3938"}, "query": {"anchor_diff": "@@ -275,6 +275,37 @@ class Segment(NamedTuple):\n if line:\n yield line\n \n+ @classmethod\n+ def split_lines_terminator(\n+ cls, segments: Iterable[\"Segment\"]\n+ ) -> Iterable[Tuple[List[\"Segment\"], bool]]:\n+ \"\"\"Split a sequence of segments in to a list of lines and a boolean to indicate if there was a new line.\n+\n+ Args:\n+ segments (Iterable[Segment]): Segments potentially containing line feeds.\n+\n+ Yields:\n+ Iterable[List[Segment]]: Iterable of segment lists, one per line.\n+ \"\"\"\n+ line: List[Segment] = []\n+ append = line.append\n+\n+ for segment in segments:\n+ if \"\\n\" in segment.text and not segment.control:\n+ text, style, _ = segment\n+ while text:\n+ _text, new_line, text = text.partition(\"\\n\")\n+ if _text:\n+ append(cls(_text, style))\n+ if new_line:\n+ yield (line, True)\n+ line = []\n+ append = line.append\n+ else:\n+ append(segment)\n+ if line:\n+ yield (line, False)\n+\n @classmethod\n def split_and_crop_lines(\n cls,", "anchor_file": "rich/segment.py", "intent": "fix background style with soft wrap\n\nFixes https://github.com/Textualize/rich/issues/3838\n\nfix background style with soft wrap\n\nchangelog\n\nsplit lines terminator\n\ntest"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "618496288c41da835683ec149432c4869722779f", "candidate_corpus": {"base_commit": "618496288c41da835683ec149432c4869722779f", "type": "repo_at_base_commit"}, "gold": {"files": ["axum/src/extract/ws.rs", "axum/Cargo.toml"], "given_files": ["axum-macros/src/debug_handler.rs"]}, "id": "8c520f13d3c6fb9022da26c8", "metadata": {"changed_files": [".github/workflows/CI.yml", "Cargo.lock", "Cargo.toml", "axum-macros/src/debug_handler.rs", "axum/Cargo.toml", "axum/src/extract/ws.rs", "deny.toml", "examples/Cargo.lock"], "created_at": "2026-10-08T13:22:09Z", "fix_commit": "dcfd5e3442b2a8b021ccc954501157ebd602d2a2", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "axum/src/extract/ws.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 3, "deletions": 3, "is_test": false, "path": "axum/Cargo.toml", "signals": ["path_token_overlap", "shared_config_or_schema"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"axum/Cargo.toml": ["axum"], "axum/src/extract/ws.rs": ["axum"]}}, "merged_at": "2026-10-09T21:28:08Z", "pr": 3935, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"], "source_pr": "https://github.com/tokio-rs/axum/pull/3935"}, "query": {"anchor_diff": "@@ -871,7 +871,7 @@ fn skip_next_arg(arg: &FnArg, kind: FunctionKind) -> bool {\n .path\n .segments\n .last()\n- .map_or(true, |path_segment| path_segment.ident != \"Next\")\n+ .is_none_or(|path_segment| path_segment.ident != \"Next\")\n } else {\n true\n }", "anchor_file": "axum-macros/src/debug_handler.rs", "intent": "Update tungstenite version to 0.30.0\n\nUpdates tungstenite dependency to the latest version. Changes can be seen here https://github.com/snapview/tungstenite-rs/blob/master/CHANGELOG.md#0300 but to save a click:\n\n> * Reject non-compliant clients (incorrect Sec-WebSocket-Key length/format) on the server side.\n> * Update rand and sha dependencies and raise MSRV to 1.85.\n\nUpdate tungstenite version to 0.30.0\n\nAppease CI denys reduce tungstenite features.\n\nApply clippy suggestion\n\nFix axum crate clippy failure\n\nUpdate MSRV in CI file\n\nRespond to review feedback\n\nBump sha1"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "618496288c41da835683ec149432c4869722779f", "candidate_corpus": {"base_commit": "618496288c41da835683ec149432c4869722779f", "type": "repo_at_base_commit"}, "gold": {"files": ["axum-macros/src/debug_handler.rs", "axum/Cargo.toml"], "given_files": ["axum/src/extract/ws.rs"]}, "id": "f6bd53a23d8207bc01dc66a2", "metadata": {"changed_files": [".github/workflows/CI.yml", "Cargo.lock", "Cargo.toml", "axum-macros/src/debug_handler.rs", "axum/Cargo.toml", "axum/src/extract/ws.rs", "deny.toml", "examples/Cargo.lock"], "created_at": "2026-10-08T13:22:09Z", "fix_commit": "dcfd5e3442b2a8b021ccc954501157ebd602d2a2", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "axum-macros/src/debug_handler.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 3, "deletions": 3, "is_test": false, "path": "axum/Cargo.toml", "signals": ["path_token_overlap", "shared_config_or_schema"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"axum-macros/src/debug_handler.rs": ["axum"], "axum/Cargo.toml": ["axum"]}}, "merged_at": "2026-10-09T21:28:08Z", "pr": 3935, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"], "source_pr": "https://github.com/tokio-rs/axum/pull/3935"}, "query": {"anchor_diff": "@@ -526,7 +526,7 @@ where\n if parts\n .extensions\n .get::()\n- .map_or(true, |p| p.as_str() != \"websocket\")\n+ .is_none_or(|p| p.as_str() != \"websocket\")\n {\n return Err(InvalidProtocolPseudoheader.into());\n }", "anchor_file": "axum/src/extract/ws.rs", "intent": "Update tungstenite version to 0.30.0\n\nUpdates tungstenite dependency to the latest version. Changes can be seen here https://github.com/snapview/tungstenite-rs/blob/master/CHANGELOG.md#0300 but to save a click:\n\n> * Reject non-compliant clients (incorrect Sec-WebSocket-Key length/format) on the server side.\n> * Update rand and sha dependencies and raise MSRV to 1.85.\n\nUpdate tungstenite version to 0.30.0\n\nAppease CI denys reduce tungstenite features.\n\nApply clippy suggestion\n\nFix axum crate clippy failure\n\nUpdate MSRV in CI file\n\nRespond to review feedback\n\nBump sha1"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "6764b24739b580c0c32ff5ef0b971ed4cfcf4f75", "candidate_corpus": {"base_commit": "6764b24739b580c0c32ff5ef0b971ed4cfcf4f75", "type": "repo_at_base_commit"}, "gold": {"files": ["rich/live_render.py", "tests/test_live.py"], "given_files": ["rich/live.py"]}, "id": "2217175cefcde25b74e34de5", "metadata": {"changed_files": ["CHANGELOG.md", "rich/live.py", "rich/live_render.py", "tests/test_live.py"], "created_at": "2026-01-22T16:56:20Z", "fix_commit": "e9a5680682e0dbaf9e0f3f0fc2a771612307bc3d", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 12, "deletions": 2, "is_test": false, "path": "rich/live_render.py", "signals": ["same_component", "path_token_overlap", "anchor_diff_mentions_gold_module", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 18, "deletions": 0, "is_test": true, "path": "tests/test_live.py", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"rich/live_render.py": ["live", "rich"], "tests/test_live.py": ["live"]}}, "merged_at": "2026-01-22T17:03:12Z", "pr": 3934, "ripple_relation": ["same_component", "path_token_overlap", "anchor_diff_mentions_gold_module", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/Textualize/rich/pull/3934"}, "query": {"anchor_diff": "@@ -166,7 +166,11 @@ class Live(JupyterMixin, RenderHook):\n finally:\n self._disable_redirect_io()\n self.console.pop_render_hook()\n- if not self._alt_screen and self.console.is_terminal:\n+ if (\n+ not self._alt_screen\n+ and self.console.is_terminal\n+ and self._live_render.last_render_height\n+ ):\n self.console.line()\n self.console.show_cursor(True)\n if self._alt_screen:", "anchor_file": "rich/live.py", "intent": "empty live\n\nFixes https://github.com/Textualize/rich/issues/3796\n\nempty live"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "6764b24739b580c0c32ff5ef0b971ed4cfcf4f75", "candidate_corpus": {"base_commit": "6764b24739b580c0c32ff5ef0b971ed4cfcf4f75", "type": "repo_at_base_commit"}, "gold": {"files": ["rich/live.py", "tests/test_live.py"], "given_files": ["rich/live_render.py"]}, "id": "f2e1f54383d679b9e29dc4b2", "metadata": {"changed_files": ["CHANGELOG.md", "rich/live.py", "rich/live_render.py", "tests/test_live.py"], "created_at": "2026-01-22T16:56:20Z", "fix_commit": "e9a5680682e0dbaf9e0f3f0fc2a771612307bc3d", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 5, "deletions": 1, "is_test": false, "path": "rich/live.py", "signals": ["same_component", "path_token_overlap", "anchor_diff_mentions_gold_module", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 18, "deletions": 0, "is_test": true, "path": "tests/test_live.py", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"rich/live.py": ["live", "rich"], "tests/test_live.py": ["live"]}}, "merged_at": "2026-01-22T17:03:12Z", "pr": 3934, "ripple_relation": ["same_component", "path_token_overlap", "anchor_diff_mentions_gold_module", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/Textualize/rich/pull/3934"}, "query": {"anchor_diff": "@@ -1,5 +1,4 @@\n-from typing import Optional, Tuple, Literal\n-\n+from typing import Literal, Optional, Tuple\n \n from ._loop import loop_last\n from .console import Console, ConsoleOptions, RenderableType, RenderResult\n@@ -30,6 +29,17 @@ class LiveRender:\n self.vertical_overflow = vertical_overflow\n self._shape: Optional[Tuple[int, int]] = None\n \n+ @property\n+ def last_render_height(self) -> int:\n+ \"\"\"The number of lines in the last render (may be 0 if nothing was rendered).\n+\n+ Returns:\n+ Height in lines\n+ \"\"\"\n+ if self._shape is None:\n+ return 0\n+ return self._shape[1]\n+\n def set_renderable(self, renderable: RenderableType) -> None:\n \"\"\"Set a new renderable.", "anchor_file": "rich/live_render.py", "intent": "empty live\n\nFixes https://github.com/Textualize/rich/issues/3796\n\nempty live"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "90f299cb721bf930ba26c0f373b8b3d2e8295ec7", "candidate_corpus": {"base_commit": "90f299cb721bf930ba26c0f373b8b3d2e8295ec7", "type": "repo_at_base_commit"}, "gold": {"files": ["axum/src/form.rs", "axum/src/util.rs", "axum/src/extract/query.rs"], "given_files": ["axum/src/json.rs"]}, "id": "1dc5b0c69a0f255577100a2c", "metadata": {"changed_files": ["axum/src/extract/query.rs", "axum/src/form.rs", "axum/src/json.rs", "axum/src/util.rs"], "created_at": "2026-10-05T06:04:06Z", "fix_commit": "853067671a38632ceab12cc6227c046152db779c", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 2, "deletions": 2, "is_test": false, "path": "axum/src/form.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 15, "deletions": 0, "is_test": false, "path": "axum/src/util.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 2, "deletions": 2, "is_test": false, "path": "axum/src/extract/query.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"axum/src/extract/query.rs": ["query", "axum"], "axum/src/form.rs": ["form", "axum"], "axum/src/util.rs": ["axum"]}}, "merged_at": "2026-10-05T21:38:04Z", "pr": 3924, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/tokio-rs/axum/pull/3924"}, "query": {"anchor_diff": "@@ -181,16 +181,19 @@ where\n }\n }\n \n- let mut deserializer = serde_json::Deserializer::from_slice(bytes);\n-\n- serde_path_to_error::deserialize(&mut deserializer)\n- .map_err(make_rejection)\n- .and_then(|value| {\n- deserializer\n- .end()\n- .map(|()| Self(value))\n- .map_err(|err| JsonSyntaxError::from_err(err).into())\n- })\n+ // like `deserialize_with_error_path`, which can't be used here because of `end`\n+ serde_json::from_slice(bytes).map(Self).or_else(|_| {\n+ let mut deserializer = serde_json::Deserializer::from_slice(bytes);\n+\n+ serde_path_to_error::deserialize(&mut deserializer)\n+ .map_err(make_rejection)\n+ .and_then(|value| {\n+ deserializer\n+ .end()\n+ .map(|()| Self(value))\n+ .map_err(|err| JsonSyntaxError::from_err(err).into())\n+ })\n+ })\n }\n }", "anchor_file": "axum/src/json.rs", "intent": "Perf/deserialize error path on failure\n\n## Motivation\n\n`Json`, `Form` and `Query` always deserialize through `serde_path_to_error`, which allocates for every field it visits so that it can report where an error happened. That's only useful when deserialization fails, but every successful request pays for it.\n\nMeasured in-process through `Router` on an M3 Pro, a POST with a three-field JSON body goes from 25 to 19 allocations and a two-field query from 22 to 18. In criterion that's 1.21x for receiving JSON, 1.24x for a form, 1.18x for a query and 1.12x for echoing JSON back, with an unrelated handler unchanged.\n\n## Solution\n\nDeserialize without path tracking first, and only if that fails do it again through `serde_path_to_error` to build the rejection. Error messages and rejection types stay the same, since the second pass sees the same input.\n\n`Form` and `Query` share a small `deserialize_with_error_path` helper. `Json` does the same with `serde_json::from_slice` as the first attempt, since it also has to call `end()` on the deserializer to reject trailing input, which the helper can't do.\n\naxum: only track the error path once deserialization has failed\n\nMerge branch 'tokio-rs:main' into perf/deserialize-error-path-on-failure"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "90f299cb721bf930ba26c0f373b8b3d2e8295ec7", "candidate_corpus": {"base_commit": "90f299cb721bf930ba26c0f373b8b3d2e8295ec7", "type": "repo_at_base_commit"}, "gold": {"files": ["axum/src/form.rs", "axum/src/json.rs", "axum/src/extract/query.rs"], "given_files": ["axum/src/util.rs"]}, "id": "df183a377bcc3a791c08852e", "metadata": {"changed_files": ["axum/src/extract/query.rs", "axum/src/form.rs", "axum/src/json.rs", "axum/src/util.rs"], "created_at": "2026-10-05T06:04:06Z", "fix_commit": "853067671a38632ceab12cc6227c046152db779c", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 2, "deletions": 2, "is_test": false, "path": "axum/src/form.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 13, "deletions": 10, "is_test": false, "path": "axum/src/json.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 2, "deletions": 2, "is_test": false, "path": "axum/src/extract/query.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"axum/src/extract/query.rs": ["query", "axum"], "axum/src/form.rs": ["form", "axum"], "axum/src/json.rs": ["json", "axum"]}}, "merged_at": "2026-10-05T21:38:04Z", "pr": 3924, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/tokio-rs/axum/pull/3924"}, "query": {"anchor_diff": "@@ -9,6 +9,21 @@ use std::{\n };\n use tower::Service;\n \n+/// Deserializes a `T`, and only if that fails does it again through `serde_path_to_error` to report\n+/// where the error is. Tracking the path allocates for every field, so it's skipped when\n+/// deserialization succeeds.\n+#[cfg(any(feature = \"form\", feature = \"query\"))]\n+pub(crate) fn deserialize_with_error_path<'de, D, T>(\n+ mut make_deserializer: impl FnMut() -> D,\n+) -> Result>\n+where\n+ D: serde_core::Deserializer<'de>,\n+ T: serde_core::Deserialize<'de>,\n+{\n+ T::deserialize(make_deserializer())\n+ .or_else(|_| serde_path_to_error::deserialize(make_deserializer()))\n+}\n+\n #[derive(Clone, Debug, PartialEq, Eq, Hash)]\n pub(crate) struct PercentDecodedStr(Arc);", "anchor_file": "axum/src/util.rs", "intent": "Perf/deserialize error path on failure\n\n## Motivation\n\n`Json`, `Form` and `Query` always deserialize through `serde_path_to_error`, which allocates for every field it visits so that it can report where an error happened. That's only useful when deserialization fails, but every successful request pays for it.\n\nMeasured in-process through `Router` on an M3 Pro, a POST with a three-field JSON body goes from 25 to 19 allocations and a two-field query from 22 to 18. In criterion that's 1.21x for receiving JSON, 1.24x for a form, 1.18x for a query and 1.12x for echoing JSON back, with an unrelated handler unchanged.\n\n## Solution\n\nDeserialize without path tracking first, and only if that fails do it again through `serde_path_to_error` to build the rejection. Error messages and rejection types stay the same, since the second pass sees the same input.\n\n`Form` and `Query` share a small `deserialize_with_error_path` helper. `Json` does the same with `serde_json::from_slice` as the first attempt, since it also has to call `end()` on the deserializer to reject trailing input, which the helper can't do.\n\naxum: only track the error path once deserialization has failed\n\nMerge branch 'tokio-rs:main' into perf/deserialize-error-path-on-failure"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "16b5f99d16773ba87cd1a2e40976a2cd3648b75f", "candidate_corpus": {"base_commit": "16b5f99d16773ba87cd1a2e40976a2cd3648b75f", "type": "repo_at_base_commit"}, "gold": {"files": ["tests/integration_tests.rs"], "given_files": ["src/bin/bat/clap_app.rs"]}, "id": "231c6010f07a642db93e0ae8", "metadata": {"changed_files": ["CHANGELOG.md", "src/bin/bat/clap_app.rs", "tests/examples/bat-show-all.conf", "tests/integration_tests.rs"], "created_at": "2026-09-04T10:01:56Z", "fix_commit": "7323a7514f7601737640e7172be115127d6db08c", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 24, "deletions": 0, "is_test": true, "path": "tests/integration_tests.rs", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": [], "nonfatal_hits": {}}, "merged_at": "2026-09-04T19:10:30Z", "pr": 3912, "ripple_relation": ["shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/sharkdp/bat/pull/3912"}, "query": {"anchor_diff": "@@ -52,6 +52,7 @@ pub fn build_app(interactive_output: bool) -> Command {\n .long(\"show-all\")\n .alias(\"show-nonprintable\")\n .short('A')\n+ .overrides_with(\"show-all\")\n .action(ArgAction::SetTrue)\n .conflicts_with(\"language\")\n .help(\"Show non-printable characters (space, tab, newline, ..).\")\n@@ -171,6 +172,7 @@ pub fn build_app(interactive_output: bool) -> Command {\n Arg::new(\"diff\")\n .long(\"diff\")\n .short('d')\n+ .overrides_with(\"diff\")\n .action(ArgAction::SetTrue)\n .conflicts_with(\"line-range\")\n .help(\"Only show lines that have been added/removed/modified.\")\n@@ -235,6 +237,7 @@ pub fn build_app(interactive_output: bool) -> Command {\n Arg::new(\"chop-long-lines\")\n .long(\"chop-long-lines\")\n .short('S')\n+ .overrides_with(\"chop-long-lines\")\n .action(ArgAction::SetTrue)\n .help(\"Truncate all lines longer than screen width. Alias for '--wrap=never'.\"),\n )\n@@ -473,6 +476,7 @@ pub fn build_app(interactive_output: bool) -> Command {\n Arg::new(\"squeeze-blank\")\n .long(\"squeeze-blank\")\n .short('s')\n+ .overrides_with(\"squeeze-blank\")\n .action(ArgAction::SetTrue)\n .help(\"Squeeze consecutive empty lines.\")\n .long_help(\"Squeeze consecutive empty lines into a single empty line.\")\n@@ -598,6 +602,7 @@ pub fn build_app(interactive_output: bool) -> Command {\n Arg::new(\"unbuffered\")\n .short('u')\n .long(\"unbuffered\")\n+ .overrides_with(\"unbuffered\")\n .action(ArgAction::SetTrue)\n .help(\"Enable unbuffered input reading for streaming use cases.\")\n .long_help(\n@@ -619,6 +624,7 @@ pub fn build_app(interactive_output: bool) -> Command {\n .arg(\n Arg::new(\"no-custom-assets\")\n .long(\"no-custom-assets\")\n+ .overrides_with(\"no-custom-assets\")\n .action(ArgAction::SetTrue)\n .hide(true)\n .help(\"Do not load custom assets\"),\n@@ -699,6 +705,7 @@ pub fn build_app(interactive_output: bool) -> Command {\n Arg::new(\"quiet-empty\")\n .long(\"quiet-empty\")\n .short('E')\n+ .overrides_with(\"quiet-empty\")\n .action(ArgAction::SetTrue)\n .help(\"Produce no output when the input is empty.\")\n .long_help(\n@@ -717,6 +724,7 @@ pub fn build_app(interactive_output: bool) -> Command {\n .arg(\n Arg::new(\"set-terminal-title\")\n .long(\"set-terminal-title\")\n+ .overrides_with(\"set-terminal-title\")\n .action(ArgAction::SetTrue)\n .hide_short_help(true)\n .help(\"Sets terminal title to filenames when using a pager.\"),", "anchor_file": "src/bin/bat/clap_app.rs", "intent": "Allow boolean flags to be repeated\n\nbat prepends the arguments from its config file to the command line. So a user who keeps `--show-all` in `~/.config/bat/config` and then types `bat -A file` passes the flag twice, and clap rejects it:\n\n```console\n$ printf -- '--show-all\\n' > ~/.config/bat/config\n$ bat -A src/main.rs\nerror: the argument '--show-all' cannot be used multiple times\n$ echo $?\n2\n```\n\nThe file is never displayed. `--plain` and `--number` do not have this problem, because they already override themselves; `--show-all` and seven others do not.\n\nMeasured on `master` and this branch, once through the config file and once by passing the flag twice directly:\n\n| flag | master: config + CLI | master: CLI twice | this branch |\n|---|---|---|---|\n| `--show-all` | error | error | ok |\n| `--diff` | error | error | ok |\n| `--chop-long-lines` | error | error | ok |\n| `--squeeze-blank` | error | error | ok |\n| `--unbuffered` | error | error | ok |\n| `--quiet-empty` | error | error | ok |\n| `--no-custom-assets` | error | error | ok |\n| `--set-terminal-title` | error | error | ok |\n\nThe fix is `.overrides_with(\"\")`, which is what `plain`, `number`, `number-nonblank`, `force-colorization` and `no-paging` already do.\n\nTwo things I checked rather than assumed, since `overrides_with` on a `SetTrue` flag could plausibly make the second occurrence turn the first one off, or interfere with the existing conflict rules:\n\n- Giving a flag twice produces **byte-identical output** to giving it once, for `-A`, `-s`, `-d` and `--chop-long-lines`. The flag still takes effect.\n- `-A -l rust` still exits 2, so `--show-all`'s `conflicts_with(\"language\")` is unaffected.\n\nSingle-use output is byte-identical to `master` for every flag touched.\n\nThe two added tests fail on `master` — I checke\n...[truncated]"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "83366c2b275599366d0b914b27128141cf4ca936", "candidate_corpus": {"base_commit": "83366c2b275599366d0b914b27128141cf4ca936", "type": "repo_at_base_commit"}, "gold": {"files": ["axum/src/routing/tests/merge.rs"], "given_files": ["axum/src/routing/path_router.rs"]}, "id": "8d292db1f2a1ab4401be6904", "metadata": {"changed_files": ["axum/CHANGELOG.md", "axum/src/routing/path_router.rs", "axum/src/routing/tests/merge.rs"], "created_at": "2026-09-29T14:36:30Z", "fix_commit": "f8b02f22cf10bee707bda19b58265b9e33677535", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 46, "deletions": 0, "is_test": true, "path": "axum/src/routing/tests/merge.rs", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"axum/src/routing/tests/merge.rs": ["merge", "axum", "routing"]}}, "merged_at": "2026-09-30T06:02:38Z", "pr": 3909, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/tokio-rs/axum/pull/3909"}, "query": {"anchor_diff": "@@ -124,7 +124,8 @@ where\n \n match route {\n Endpoint::MethodRouter(method_router) => self.route(path, method_router)?,\n- Endpoint::Route(route) => self.route_service(path, route)?,\n+ // `route_service` would wrap this `Route` in another `Route`\n+ endpoint @ Endpoint::Route(_) => self.route_endpoint(path, endpoint)?,\n }\n }", "anchor_file": "axum/src/routing/path_router.rs", "intent": "axum: Don't wrap merged service routes in another Route\n\n## Motivation\n\n`PathRouter::merge` hands each of the other router's endpoints back to `route` or `route_service`. For `Endpoint::Route`, the endpoint is already a `Route`, but `route_service` wraps it in `Route::new` again. Each merge of a router that holds a service route (`route_service`, `nest_service` and so on) therefore adds another layer of boxing and a `RouteFuture`. Every request to that route then pays for an extra clone of the service and an extra dynamic dispatch.\n\n## Solution\n\nInsert the existing `Route` with `route_endpoint` instead of calling `route_service`. Nothing else changes: the path is still validated and conflicts are still reported the same way.\n\nThe new test counts how many times a service is cloned while it handles a request, and checks that a merged service route is cloned as often as the same route used directly. Before this change it was cloned twice per request instead of once.\n\naxum: Don't wrap merged service routes in another Route\n\nAdd changelog entry\n\nPass the merged endpoint through unchanged"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "2ed8b010afb59c8b8463ad6818c4ee50fa1f17ee", "candidate_corpus": {"base_commit": "2ed8b010afb59c8b8463ad6818c4ee50fa1f17ee", "type": "repo_at_base_commit"}, "gold": {"files": ["tests/integration_tests.rs"], "given_files": ["src/bin/bat/app.rs"]}, "id": "ca8ed31eed5087e5b624adba", "metadata": {"changed_files": ["CHANGELOG.md", "src/bin/bat/app.rs", "tests/integration_tests.rs"], "created_at": "2026-09-04T03:01:41Z", "fix_commit": "16b5f99d16773ba87cd1a2e40976a2cd3648b75f", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 27, "deletions": 0, "is_test": true, "path": "tests/integration_tests.rs", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": [], "nonfatal_hits": {}}, "merged_at": "2026-09-04T03:46:32Z", "pr": 3908, "ripple_relation": ["shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/sharkdp/bat/pull/3908"}, "query": {"anchor_diff": "@@ -72,59 +72,12 @@ impl App {\n \n let interactive_output = std::io::stdout().is_terminal();\n \n- // Check if the -n / --number option was passed on the command line\n- // (before merging with config file and environment variables).\n- // This is needed to honor the -n flag when piping output, similar to `cat -n`.\n- // We need to handle both standalone (-n, --number) and combined short flags (-pn, -An, etc.)\n- // Note: We only check if -n appears and is not overridden by -p in the same combined flag.\n- // For combined flags like -np, -p comes after -n and overrides it, so we don't count it.\n- // For combined flags like -pn, -n comes after -p and takes effect.\n- let number_from_cli = wild::args_os().any(|arg| {\n- let arg_str = arg.to_string_lossy();\n- if arg_str == \"-n\" || arg_str == \"--number\" {\n- return true;\n- }\n- // Handle combined short flags\n- // Only count -n if its last occurrence comes after the last -p,\n- // or if -p is not present in the combined form.\n- if arg_str.starts_with('-') && !arg_str.starts_with(\"--\") && arg_str.len() > 2 {\n- let chars: Vec = arg_str.chars().skip(1).collect();\n- let n_pos = chars.iter().rposition(|&c| c == 'n');\n- let p_pos = chars.iter().rposition(|&c| c == 'p');\n- // -n is in the combined flag and either:\n- // - -p is not present, OR\n- // - -n comes after -p (so -n takes effect)\n- if let Some(n) = n_pos {\n- if p_pos.is_none() || n > p_pos.unwrap() {\n- return true;\n- }\n- }\n- }\n- false\n- });\n-\n- // Check if the -b / --number-nonblank option was passed on the command line\n- // (before merging with config file and environment variables).\n- // This is needed to honor the -b flag when piping output, similar to `cat -b`.\n- // The same combined-flag logic applies as for -n above.\n- let number_nonblank_from_cli = wild::args_os().any(|arg| {\n- let arg_str = arg.to_string_lossy();\n- if arg_str == \"-b\" || arg_str == \"--number-nonblank\" {\n- return true;\n- }\n- // Handle combined short flags by comparing the last -b and -p occurrences.\n- if arg_str.starts_with('-') && !arg_str.starts_with(\"--\") && arg_str.len() > 2 {\n- let chars: Vec = arg_str.chars().skip(1).collect();\n- let b_pos = chars.iter().rposition(|&c| c == 'b');\n- let p_pos = chars.iter().rposition(|&c| c == 'p');\n- if let Some(b) = b_pos {\n- if p_pos.is_none() || b > p_pos.unwrap() {\n- return true;\n- }\n- }\n- }\n- false\n- });\n+ // Parse the original command line separately from config and environment arguments.\n+ // Using clap here keeps CLI-only detection consistent with the final parser, including\n+ // option terminators, combined short flags, and options that take values.\n+ let cli_matches = Self::cli_matches(interactive_output);\n+ let number_from_cli = cli_matches.get_flag(\"number\");\n+ let number_nonblank_from_cli = cli_matches.get_flag(\"number-nonblank\");\n \n let matches = Self::matches(interactive_output)?;\n \n@@ -238,6 +191,10 @@ impl App {\n args\n }\n \n+ fn cli_matches(interactive_output: bool) -> ArgMatches {\n+ clap_app::build_app(interactive_output).get_matches_from(wild::args_os())\n+ }\n+\n fn matches(interactive_output: bool) -> Result {\n // Check if we should skip config file processing for special arguments\n // that don't require full application setup (version, diagnostic)", "anchor_file": "src/bin/bat/app.rs", "intent": "Use parsed CLI arguments to detect number flags\n\n## Problem\n\nFix incorrect detection of `-n` / `-b` when these strings appear in positional arguments or option values.\n\n\n`App::new()` currently scans `wild::args_os()` manually to determine whether `-n` or `-b` was supplied directly on the command line.\n\nThis scan does not implement clap's argument parsing rules. As a result, filenames after `--` and values belonging to short options can be interpreted as numbering flags.\n\nFor example:\n\n```bash\nprintf 'hello\\nworld\\n' > ./-b\nbat -- -b\n```\n\nThe `-b` argument is a filename because it appears after the option terminator. However, the manual scanner treats it as `--number-nonblank`. This can change the output by forcing line numbers and disabling loop-through mode.\n\nA similar problem occurs with short options that accept values:\n\n```bash\nbat -lbn input.txt\n```\n\nHere `bn` is the value of `-l`; it is not a combination of `-b` and `-n`.\n\n\nThe CLI-only flag detection was implemented separately from the clap command used to parse the final arguments. The manual scanner therefore does not handle:\n\n- `--` option terminators;\n- combined short options;\n- short options with attached values;\n- future changes to the argument definitions.\n\n## Solution\n\nParse the original CLI arguments once with the existing clap command and use the resulting `ArgMatches` to determine whether `number` or `number-nonblank` was supplied directly by the user.\n\nThe existing config-file and environment-variable merging logic remains unchanged. The separately parsed matches are only used for CLI-only detection.\n\nUse parsed CLI arguments to detect number flags"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "618496288c41da835683ec149432c4869722779f", "candidate_corpus": {"base_commit": "618496288c41da835683ec149432c4869722779f", "type": "repo_at_base_commit"}, "gold": {"files": ["axum/src/routing/tests/mod.rs"], "given_files": ["axum/src/routing/route.rs"]}, "id": "d74bb04ecb49672aaa3febbe", "metadata": {"changed_files": ["axum/CHANGELOG.md", "axum/src/routing/route.rs", "axum/src/routing/tests/mod.rs"], "created_at": "2026-09-28T21:51:34Z", "fix_commit": "e57b547eb95de74b73b34719dd5926254a085634", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 28, "deletions": 0, "is_test": true, "path": "axum/src/routing/tests/mod.rs", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"axum/src/routing/tests/mod.rs": ["axum", "routing"]}}, "merged_at": "2026-10-11T11:54:49Z", "pr": 3907, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/tokio-rs/axum/pull/3907"}, "query": {"anchor_diff": "@@ -159,6 +159,8 @@ impl Future for RouteFuture {\n {\n error!(\"response to CONNECT with nonempty body\");\n res = res.map(|_| Body::empty());\n+ res.headers_mut().remove(&CONTENT_LENGTH);\n+ res.headers_mut().remove(&header::TRANSFER_ENCODING);\n }\n } else if *this.top_level {\n if res.status() == http::StatusCode::METHOD_NOT_ALLOWED {", "anchor_file": "axum/src/routing/route.rs", "intent": "axum: Remove framing headers from successful CONNECT responses\n\n## Motivation\n\nFor a 2xx response to `CONNECT`, `RouteFuture` quotes RFC 9110:\n\n> A server MUST NOT send any Transfer-Encoding or Content-Length header fields in a 2xx (Successful) response to CONNECT.\n\nIt then replaces the body with `Body::empty()` but leaves the `Content-Length` and `Transfer-Encoding` headers in place. The response the router returns still carries the forbidden headers.\n\nhyper's HTTP/1 encoder already drops these headers on the wire. Anything else that sees the response after the router still gets them: outer middleware, tests that call the router with `oneshot`, and servers that don't use hyper's HTTP/1 path.\n\n## Solution\n\nRemove `Content-Length` and `Transfer-Encoding` in the same branch that empties the body. I added a regression test, `successful_connect_drops_body_and_framing_headers`, which fails without the change.\n\naxum: Remove framing headers from successful CONNECT responses\n\nAdd changelog entry"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "7a4a7a614b4893a8197d06800b241c2c28036ad4", "candidate_corpus": {"base_commit": "7a4a7a614b4893a8197d06800b241c2c28036ad4", "type": "repo_at_base_commit"}, "gold": {"files": ["rich/traceback.py"], "given_files": ["rich/scope.py"]}, "id": "14deb6ca21ee08939f33f084", "metadata": {"changed_files": ["CHANGELOG.md", "CONTRIBUTORS.md", "rich/scope.py", "rich/traceback.py"], "created_at": "2025-12-04T12:54:44Z", "fix_commit": "96dd4b60e3a7c647c43a85ad375afa690b3bb85b", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 25, "deletions": 0, "is_test": false, "path": "rich/traceback.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"rich/traceback.py": ["traceback", "rich"]}}, "merged_at": "2026-01-22T17:30:43Z", "pr": 3906, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/Textualize/rich/pull/3906"}, "query": {"anchor_diff": "@@ -8,7 +8,7 @@ from .table import Table\n from .text import Text, TextType\n \n if TYPE_CHECKING:\n- from .console import ConsoleRenderable\n+ from .console import ConsoleRenderable, OverflowMethod\n \n \n def render_scope(\n@@ -19,6 +19,8 @@ def render_scope(\n indent_guides: bool = False,\n max_length: Optional[int] = None,\n max_string: Optional[int] = None,\n+ max_depth: Optional[int] = None,\n+ overflow: Optional[\"OverflowMethod\"] = None,\n ) -> \"ConsoleRenderable\":\n \"\"\"Render python variables in a given scope.\n \n@@ -30,6 +32,8 @@ def render_scope(\n max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation.\n Defaults to None.\n max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to None.\n+ max_depth (int, optional): Maximum depths of locals before truncating, or None to disable. Defaults to None.\n+ overflow (OverflowMethod, optional): How to handle overflowing locals, or None to disable. Defaults to None.\n \n Returns:\n ConsoleRenderable: A renderable object.\n@@ -57,6 +61,8 @@ def render_scope(\n indent_guides=indent_guides,\n max_length=max_length,\n max_string=max_string,\n+ max_depth=max_depth,\n+ overflow=overflow,\n ),\n )\n return Panel.fit(", "anchor_file": "rich/scope.py", "intent": "feat: Traceback - Expose more locals rendering options\n\n## Type of changes\n\n- [ ] Bug fix\n- [x] New feature\n- [ ] Documentation / docstrings\n- [ ] Tests\n- [ ] Other\n\n## AI?\n\n- [ ] AI was used to generate this PR\n\nAI generated PRs may be accepted, but only if @willmcgugan has responded on an issue or discussion.\n\n## Checklist\n\n- [x] I've run the latest [black](https://github.com/psf/black) with default args on new code.\n- [x] I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate (see note about typos above).\n- [ ] I've added tests for new code.\n- [x] I accept that @willmcgugan may be pedantic in the code review.\n\n## Description\n\nHi! I ran into an issue where rich tracebacks were spamming my logs with deeply nested items & found no way to reduce this.\nThis PR is a simple re-implementation of the accepted PR #3415 where the author did not respond to fix merge conflicts :)\n\nPlease see the above mentioned PR for information & background.\nI simply moved over the changes\n\nfeat: Traceback - Expose more locals rendering options\n\nMerge branch 'master' into master"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "7a4a7a614b4893a8197d06800b241c2c28036ad4", "candidate_corpus": {"base_commit": "7a4a7a614b4893a8197d06800b241c2c28036ad4", "type": "repo_at_base_commit"}, "gold": {"files": ["rich/scope.py"], "given_files": ["rich/traceback.py"]}, "id": "a029a7bf3c1d40bc014d583e", "metadata": {"changed_files": ["CHANGELOG.md", "CONTRIBUTORS.md", "rich/scope.py", "rich/traceback.py"], "created_at": "2025-12-04T12:54:44Z", "fix_commit": "96dd4b60e3a7c647c43a85ad375afa690b3bb85b", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 7, "deletions": 1, "is_test": false, "path": "rich/scope.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"rich/scope.py": ["rich"]}}, "merged_at": "2026-01-22T17:30:43Z", "pr": 3906, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/Textualize/rich/pull/3906"}, "query": {"anchor_diff": "@@ -33,6 +33,7 @@ from .console import (\n Console,\n ConsoleOptions,\n ConsoleRenderable,\n+ OverflowMethod,\n Group,\n RenderResult,\n group,\n@@ -91,8 +92,10 @@ def install(\n show_locals: bool = False,\n locals_max_length: int = LOCALS_MAX_LENGTH,\n locals_max_string: int = LOCALS_MAX_STRING,\n+ locals_max_depth: Optional[int] = None,\n locals_hide_dunder: bool = True,\n locals_hide_sunder: Optional[bool] = None,\n+ locals_overflow: Optional[OverflowMethod] = None,\n indent_guides: bool = True,\n suppress: Iterable[Union[str, ModuleType]] = (),\n max_frames: int = 100,\n@@ -114,8 +117,10 @@ def install(\n locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation.\n Defaults to 10.\n locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80.\n+ locals_max_depth (int, optional): Maximum depths of locals before truncating, or None to disable. Defaults to None.\n locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True.\n locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False.\n+ locals_overflow (OverflowMethod, optional): How to handle overflowing locals, or None to disable. Defaults to None.\n indent_guides (bool, optional): Enable indent guides in code and locals. Defaults to True.\n suppress (Sequence[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback.\n \n@@ -148,8 +153,10 @@ def install(\n show_locals=show_locals,\n locals_max_length=locals_max_length,\n locals_max_string=locals_max_string,\n+ locals_max_depth=locals_max_depth,\n locals_hide_dunder=locals_hide_dunder,\n locals_hide_sunder=bool(locals_hide_sunder),\n+ locals_overflow=locals_overflow,\n indent_guides=indent_guides,\n suppress=suppress,\n max_frames=max_frames,\n@@ -268,8 +275,10 @@ class Traceback:\n locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation.\n Defaults to 10.\n locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80.\n+ locals_max_depth (int, optional): Maximum depths of locals before truncating, or None to disable. Defaults to None.\n locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True.\n locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False.\n+ locals_overflow (OverflowMethod, optional): How to handle overflowing locals, or None to disable. Defaults to None.\n suppress (Sequence[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback.\n max_frames (int): Maximum number of frames to show in a traceback, 0 for no maximum. Defaults to 100.\n \n@@ -295,8 +304,10 @@ class Traceback:\n show_locals: bool = False,\n locals_max_length: int = LOCALS_MAX_LENGTH,\n locals_max_string: int = LOCALS_MAX_STRING,\n+ locals_max_depth: Optional[int] = None,\n locals_hide_dunder: bool = True,\n locals_hide_sunder: bool = False,\n+ locals_overlow: Optional[OverflowMethod] = None,\n indent_guides: bool = True,\n suppress: Iterable[Union[str, ModuleType]] = (),\n max_frames: int = 100,\n@@ -320,8 +331,10 @@ class Traceback:\n self.indent_guides = indent_guides\n self.locals_max_length = locals_max_length\n self.locals_max_string = locals_max_string\n+ self.locals_max_depth = locals_max_depth\n self.locals_hide_dunder = locals_hide_dunder\n self.locals_hide_sunder = locals_hide_sunder\n+ self.locals_overflow = locals_overlow\n \n self.suppress: Sequence[str] = []\n for suppress_entity in suppress:\n@@ -351,8 +364,10 @@ class Traceback:\n show_locals: bool = False,\n locals_max_length: int = LOCALS_MAX_LENGTH,\n locals_max_string: int = LOCALS_MAX_STRING,\n+ locals_max_depth: Optional[int] = None,\n locals_hide_dunder: bool = True,\n locals_hide_sunder: bool = False,\n+ locals_overflow: Optional[OverflowMethod] = None,\n indent_guides: bool = True,\n suppress: Iterable[Union[str, ModuleType]] = (),\n max_frames: int = 100,\n@@ -372,9 +387,11 @@ class Traceback:\n indent_guides (bool, optional): Enable indent guides in code and locals. Defaults to True.\n locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation.\n Defaults to 10.\n+ locals_max_depth (int, optional): Maximum depths of locals before truncating, or None to disable. Defaults to None.\n locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80.\n locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True.\n locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False.\n+ locals_overflow (OverflowMethod, optional): How to handle overflowing locals, or None to disable. Defaults to None.\n suppress (Iterable[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback.\n max_frames (int): Maximum number of frames to show in a traceback, 0 for no maximum. Defaults to 100.\n \n@@ -388,6 +405,7 @@ class Traceback:\n show_locals=show_locals,\n locals_max_length=locals_max_length,\n locals_max_string=locals_max_string,\n+ locals_max_depth=locals_max_depth,\n locals_hide_dunder=locals_hide_dunder,\n locals_hide_sunder=locals_hide_sunder,\n )\n@@ -403,8 +421,10 @@ class Traceback:\n indent_guides=indent_guides,\n locals_max_length=locals_max_length,\n locals_max_string=locals_max_string,\n+ locals_max_depth=locals_max_depth,\n locals_hide_dunder=locals_hide_dunder,\n locals_hide_sunder=locals_hide_sunder,\n+ locals_overlow=locals_overflow,\n suppress=suppress,\n max_frames=max_frames,\n )\n@@ -419,6 +439,7 @@ class Traceback:\n show_locals: bool = False,\n locals_max_length: int = LOCALS_MAX_LENGTH,\n locals_max_string: int = LOCALS_MAX_STRING,\n+ locals_max_depth: Optional[int] = None,\n locals_hide_dunder: bool = True,\n locals_hide_sunder: bool = False,\n _visited_exceptions: Optional[Set[BaseException]] = None,\n@@ -433,6 +454,7 @@ class Traceback:\n locals_max_length (int, optional): Maximum length of containers before abbreviating, or None for no abbreviation.\n Defaults to 10.\n locals_max_string (int, optional): Maximum length of string before truncating, or None to disable. Defaults to 80.\n+ locals_max_depth (int, optional): Maximum depths of locals before truncating, or None to disable. Defaults to None.\n locals_hide_dunder (bool, optional): Hide locals prefixed with double underscore. Defaults to True.\n locals_hide_sunder (bool, optional): Hide locals prefixed with single underscore. Defaults to False.\n \n@@ -560,6 +582,7 @@ class Traceback:\n value,\n max_length=locals_max_length,\n max_string=locals_max_string,\n+ max_depth=locals_max_depth,\n )\n for key, value in get_locals(frame_summary.f_locals.items()\n...[truncated]", "anchor_file": "rich/traceback.py", "intent": "feat: Traceback - Expose more locals rendering options\n\n## Type of changes\n\n- [ ] Bug fix\n- [x] New feature\n- [ ] Documentation / docstrings\n- [ ] Tests\n- [ ] Other\n\n## AI?\n\n- [ ] AI was used to generate this PR\n\nAI generated PRs may be accepted, but only if @willmcgugan has responded on an issue or discussion.\n\n## Checklist\n\n- [x] I've run the latest [black](https://github.com/psf/black) with default args on new code.\n- [x] I've updated CHANGELOG.md and CONTRIBUTORS.md where appropriate (see note about typos above).\n- [ ] I've added tests for new code.\n- [x] I accept that @willmcgugan may be pedantic in the code review.\n\n## Description\n\nHi! I ran into an issue where rich tracebacks were spamming my logs with deeply nested items & found no way to reduce this.\nThis PR is a simple re-implementation of the accepted PR #3415 where the author did not respond to fix merge conflicts :)\n\nPlease see the above mentioned PR for information & background.\nI simply moved over the changes\n\nfeat: Traceback - Expose more locals rendering options\n\nMerge branch 'master' into master"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "c44f6650aa38d4c154e3cdb7347205e03813f4d5", "candidate_corpus": {"base_commit": "c44f6650aa38d4c154e3cdb7347205e03813f4d5", "type": "repo_at_base_commit"}, "gold": {"files": ["axum/src/routing/mod.rs", "axum/src/routing/path_router.rs", "axum/src/routing/tests/mod.rs", "axum/src/routing/tests/nest.rs"], "given_files": ["axum/src/extract/matched_path.rs"]}, "id": "17c082be8aea024fc3400772", "metadata": {"changed_files": ["axum/src/docs/routing/without_v07_checks.md", "axum/src/extract/matched_path.rs", "axum/src/routing/mod.rs", "axum/src/routing/path_router.rs", "axum/src/routing/tests/mod.rs", "axum/src/routing/tests/nest.rs"], "created_at": "2026-09-11T19:11:37Z", "fix_commit": "7c3c67879dc5689a921620b1fce54c383d304d67", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 0, "deletions": 7, "is_test": false, "path": "axum/src/routing/mod.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 8, "deletions": 60, "is_test": false, "path": "axum/src/routing/path_router.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 0, "deletions": 16, "is_test": true, "path": "axum/src/routing/tests/mod.rs", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 22, "deletions": 10, "is_test": true, "path": "axum/src/routing/tests/nest.rs", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"axum/src/routing/mod.rs": ["mod", "axum"], "axum/src/routing/path_router.rs": ["axum", "path", "router"], "axum/src/routing/tests/mod.rs": ["mod", "axum"], "axum/src/routing/tests/nest.rs": ["axum"]}}, "merged_at": "2026-09-23T20:01:58Z", "pr": 3889, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/tokio-rs/axum/pull/3889"}, "query": {"anchor_diff": "@@ -407,7 +407,7 @@ mod tests {\n \n #[crate::test]\n async fn matching_colon() {\n- let app = Router::new().without_v07_checks().route(\n+ let app = Router::new().route(\n \"/:foo\",\n get(|path: MatchedPath| async move { path.as_str().to_owned() }),\n );\n@@ -427,7 +427,7 @@ mod tests {\n \n #[crate::test]\n async fn matching_asterisk() {\n- let app = Router::new().without_v07_checks().route(\n+ let app = Router::new().route(\n \"/*foo\",\n get(|path: MatchedPath| async move { path.as_str().to_owned() }),\n );", "anchor_file": "axum/src/extract/matched_path.rs", "intent": "axum: remove v07 path checks\n\n## Motivation\n\nWhen we changed route capture syntax between 0.7 and 0.8, we've added a check that routes do not start with a colon or a star so that we panicked early when a user just upgraded but didn't change their routes.\n\nAlong with that we've added `without_v07_checks` if someone actually wanted to have path segment starting with a colon.\n\n0.8.0 was released in January 2025 so users had 20 months already to upgrade. Unless someone goes directly from 0.7 to 0.9, this should not affect them.\n\n## Solution\n\nRemove the checks and configuration.\n\naxum: remove v07 path checks"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "c44f6650aa38d4c154e3cdb7347205e03813f4d5", "candidate_corpus": {"base_commit": "c44f6650aa38d4c154e3cdb7347205e03813f4d5", "type": "repo_at_base_commit"}, "gold": {"files": ["axum/src/routing/mod.rs", "axum/src/extract/matched_path.rs", "axum/src/routing/tests/mod.rs", "axum/src/routing/tests/nest.rs"], "given_files": ["axum/src/routing/path_router.rs"]}, "id": "8a4f714f9b7e8926242fe9f1", "metadata": {"changed_files": ["axum/src/docs/routing/without_v07_checks.md", "axum/src/extract/matched_path.rs", "axum/src/routing/mod.rs", "axum/src/routing/path_router.rs", "axum/src/routing/tests/mod.rs", "axum/src/routing/tests/nest.rs"], "created_at": "2026-09-11T19:11:37Z", "fix_commit": "7c3c67879dc5689a921620b1fce54c383d304d67", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 0, "deletions": 7, "is_test": false, "path": "axum/src/routing/mod.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 2, "deletions": 2, "is_test": false, "path": "axum/src/extract/matched_path.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 0, "deletions": 16, "is_test": true, "path": "axum/src/routing/tests/mod.rs", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 22, "deletions": 10, "is_test": true, "path": "axum/src/routing/tests/nest.rs", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"axum/src/extract/matched_path.rs": ["axum", "path"], "axum/src/routing/mod.rs": ["axum", "routing"], "axum/src/routing/tests/mod.rs": ["axum", "routing"], "axum/src/routing/tests/nest.rs": ["axum", "routing"]}}, "merged_at": "2026-09-23T20:01:58Z", "pr": 3889, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/tokio-rs/axum/pull/3889"}, "query": {"anchor_diff": "@@ -16,59 +16,28 @@ use super::{\n pub(super) struct PathRouter {\n routes: Vec>,\n node: Arc,\n- v7_checks: bool,\n }\n \n-fn validate_path(v7_checks: bool, path: &str) -> Result<(), &'static str> {\n+fn validate_path(path: &str) -> Result<(), &'static str> {\n if path.is_empty() {\n return Err(\"Paths must start with a `/`. Use \\\"/\\\" for root routes\");\n } else if !path.starts_with('/') {\n return Err(\"Paths must start with a `/`\");\n }\n \n- if v7_checks {\n- validate_v07_paths(path)?;\n- }\n-\n Ok(())\n }\n \n-fn validate_v07_paths(path: &str) -> Result<(), &'static str> {\n- path.split('/')\n- .find_map(|segment| {\n- if segment.starts_with(':') {\n- Some(Err(\n- \"Path segments must not start with `:`. For capture groups, use \\\n- `{capture}`. If you meant to literally match a segment starting with \\\n- a colon, call `without_v07_checks` on the router.\",\n- ))\n- } else if segment.starts_with('*') {\n- Some(Err(\n- \"Path segments must not start with `*`. For wildcard capture, use \\\n- `{*wildcard}`. If you meant to literally match a segment starting with \\\n- an asterisk, call `without_v07_checks` on the router.\",\n- ))\n- } else {\n- None\n- }\n- })\n- .unwrap_or(Ok(()))\n-}\n-\n impl PathRouter\n where\n S: Clone + Send + Sync + 'static,\n {\n- pub(super) fn without_v07_checks(&mut self) {\n- self.v7_checks = false;\n- }\n-\n pub(super) fn route(\n &mut self,\n path: &str,\n method_router: MethodRouter,\n ) -> Result<(), Cow<'static, str>> {\n- validate_path(self.v7_checks, path)?;\n+ validate_path(path)?;\n \n if let Some((route_id, Endpoint::MethodRouter(prev_method_router))) = self\n .node\n@@ -122,7 +91,7 @@ where\n path: &str,\n endpoint: Endpoint,\n ) -> Result<(), Cow<'static, str>> {\n- validate_path(self.v7_checks, path)?;\n+ validate_path(path)?;\n \n self.new_route(path, endpoint)?;\n \n@@ -144,14 +113,7 @@ where\n }\n \n pub(super) fn merge(&mut self, other: Self) -> Result<(), Cow<'static, str>> {\n- let Self {\n- routes,\n- node,\n- v7_checks,\n- } = other;\n-\n- // If either of the two did not allow paths starting with `:` or `*`, do not allow them for the merged router either.\n- self.v7_checks |= v7_checks;\n+ let Self { routes, node } = other;\n \n for (id, route) in routes.into_iter().enumerate() {\n let route_id = RouteId(id);\n@@ -174,14 +136,9 @@ where\n path_to_nest_at: &str,\n router: Self,\n ) -> Result<(), Cow<'static, str>> {\n- let prefix = validate_nest_path(self.v7_checks, path_to_nest_at)?;\n+ let prefix = validate_nest_path(path_to_nest_at)?;\n \n- let Self {\n- routes,\n- node,\n- // Ignore the configuration of the nested router\n- v7_checks: _,\n- } = router;\n+ let Self { routes, node } = router;\n \n for (id, endpoint) in routes.into_iter().enumerate() {\n let route_id = RouteId(id);\n@@ -219,7 +176,7 @@ where\n T::Response: IntoResponse,\n T::Future: Send + 'static,\n {\n- let path = validate_nest_path(self.v7_checks, path_to_nest_at)?;\n+ let path = validate_nest_path(path_to_nest_at)?;\n let prefix = path;\n \n let path = if path.ends_with('/') {\n@@ -265,7 +222,6 @@ where\n Self {\n routes,\n node: self.node,\n- v7_checks: self.v7_checks,\n }\n }\n \n@@ -294,7 +250,6 @@ where\n Self {\n routes,\n node: self.node,\n- v7_checks: self.v7_checks,\n }\n }\n \n@@ -317,7 +272,6 @@ where\n PathRouter {\n routes,\n node: self.node,\n- v7_checks: self.v7_checks,\n }\n }\n \n@@ -377,7 +331,6 @@ impl Default for PathRouter {\n Self {\n routes: Default::default(),\n node: Default::default(),\n- v7_checks: true,\n }\n }\n }\n@@ -396,7 +349,6 @@ impl Clone for PathRouter {\n Self {\n routes: self.routes.clone(),\n node: self.node.clone(),\n- v7_checks: self.v7_checks,\n }\n }\n }\n@@ -442,7 +394,7 @@ impl fmt::Debug for Node {\n }\n }\n \n-fn validate_nest_path(v7_checks: bool, path: &str) -> Result<&str, &'static str> {\n+fn validate_nest_path(path: &str) -> Result<&str, &'static str> {\n if !path.starts_with('/') {\n return Err(\"Nesting paths must start with a `/`.\");\n }\n@@ -456,10 +408,6 @@ fn validate_nest_path(v7_checks: bool, path: &str) -> Result<&str, &'static str>\n return Err(\"Invalid route: nested routes cannot contain wildcards (*)\");\n }\n \n- if v7_checks {\n- validate_v07_paths(path)?;\n- }\n-\n Ok(path)\n }", "anchor_file": "axum/src/routing/path_router.rs", "intent": "axum: remove v07 path checks\n\n## Motivation\n\nWhen we changed route capture syntax between 0.7 and 0.8, we've added a check that routes do not start with a colon or a star so that we panicked early when a user just upgraded but didn't change their routes.\n\nAlong with that we've added `without_v07_checks` if someone actually wanted to have path segment starting with a colon.\n\n0.8.0 was released in January 2025 so users had 20 months already to upgrade. Unless someone goes directly from 0.7 to 0.9, this should not affect them.\n\n## Solution\n\nRemove the checks and configuration.\n\naxum: remove v07 path checks"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "66ad54c27dad68669bf7600722c3e27ceccec2c3", "candidate_corpus": {"base_commit": "66ad54c27dad68669bf7600722c3e27ceccec2c3", "type": "repo_at_base_commit"}, "gold": {"files": ["tests/integration_tests.rs"], "given_files": ["src/input.rs"]}, "id": "ca96b942c30f53b27f03157f", "metadata": {"changed_files": ["CHANGELOG.md", "src/input.rs", "tests/integration_tests.rs"], "created_at": "2026-08-02T08:53:20Z", "fix_commit": "2ed8b010afb59c8b8463ad6818c4ee50fa1f17ee", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 20, "deletions": 0, "is_test": true, "path": "tests/integration_tests.rs", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": [], "nonfatal_hits": {}}, "merged_at": "2026-09-03T19:07:15Z", "pr": 3877, "ripple_relation": ["shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/sharkdp/bat/pull/3877"}, "query": {"anchor_diff": "@@ -9,6 +9,8 @@ use content_inspector::{self, ContentType};\n \n use crate::error::*;\n \n+const CONTENT_INSPECTION_LIMIT: usize = 1024;\n+\n /// A description of an Input source.\n /// This tells bat how to refer to the input.\n #[derive(Clone)]\n@@ -263,10 +265,29 @@ impl<'a> InputReader<'a> {\n }\n \n pub(crate) fn try_new(mut reader: R) -> io::Result> {\n+ // content_inspector scans at most 1024 bytes. Capture the already-buffered\n+ // prefix before splitting out the first line so an early newline in binary\n+ // data does not shorten the inspected content. This does not consume input\n+ // or perform an additional read beyond the one read_until needs anyway.\n+ let mut inspection_prefix = {\n+ let buffered = reader.fill_buf()?;\n+ buffered[..buffered.len().min(CONTENT_INSPECTION_LIMIT)].to_vec()\n+ };\n+\n let mut first_line = vec![];\n- reader.read_until(b'\\n', &mut first_line)?;\n+ if !inspection_prefix.is_empty() {\n+ reader.read_until(b'\\n', &mut first_line)?;\n+ }\n+\n+ // A custom BufRead implementation may expose less than 1024 bytes at a\n+ // time. Keep the old behavior for long first lines in that case.\n+ let first_line_prefix_len = first_line.len().min(CONTENT_INSPECTION_LIMIT);\n+ if first_line_prefix_len > inspection_prefix.len() {\n+ inspection_prefix.clear();\n+ inspection_prefix.extend_from_slice(&first_line[..first_line_prefix_len]);\n+ }\n \n- let content_type = inspect_content_type(&first_line);\n+ let content_type = inspect_content_type(&inspection_prefix);\n \n if content_type == Some(ContentType::UTF_16LE) {\n read_utf16_line(&mut reader, &mut first_line, 0x00, 0x0A)?;\n@@ -410,6 +431,53 @@ fn non_zip_pk_prefix_is_not_treated_as_binary() {\n );\n }\n \n+#[test]\n+fn binary_detection_scans_beyond_first_line_and_preserves_input() {\n+ let mut content = vec![b'a'; CONTENT_INSPECTION_LIMIT + 1];\n+ content[1] = b'\\n';\n+ content[CONTENT_INSPECTION_LIMIT - 1] = 0;\n+\n+ let mut reader = InputReader::new(&content[..]);\n+ assert_eq!(Some(ContentType::BINARY), reader.content_type);\n+\n+ let mut replayed = Vec::new();\n+ while reader.read_line(&mut replayed).unwrap() {}\n+ assert_eq!(content, replayed);\n+\n+ drop(reader);\n+\n+ content[CONTENT_INSPECTION_LIMIT - 1] = b'a';\n+ content[CONTENT_INSPECTION_LIMIT] = 0;\n+\n+ let reader = InputReader::new(&content[..]);\n+ assert_eq!(Some(ContentType::UTF_8), reader.content_type);\n+}\n+\n+#[test]\n+fn input_detection_does_not_read_twice() {\n+ struct OneRead(Option<&'static [u8]>);\n+\n+ impl Read for OneRead {\n+ fn read(&mut self, buf: &mut [u8]) -> io::Result {\n+ match self.0.take() {\n+ None => Err(io::Error::new(\n+ io::ErrorKind::WouldBlock,\n+ \"no more data is available yet\",\n+ )),\n+ Some(content) => {\n+ buf[..content.len()].copy_from_slice(content);\n+ Ok(content.len())\n+ }\n+ }\n+ }\n+ }\n+\n+ for (content, expected) in [(&b\"text\\n\"[..], Some(ContentType::UTF_8)), (&b\"\"[..], None)] {\n+ let input = InputReader::try_new(BufReader::new(OneRead(Some(content)))).unwrap();\n+ assert_eq!(expected, input.content_type);\n+ }\n+}\n+\n #[test]\n fn input_open_returns_initial_read_errors() {\n struct FailingRead;", "anchor_file": "src/input.rs", "intent": "Detect binary content beyond the first line\n\n## Summary\n\n- inspect up to the first 1024 already-buffered bytes before splitting out the first line\n- preserve the reader's bytes, line boundaries, UTF-16 handling, and streaming behavior\n- add regressions for cross-line binary detection, the 1024-byte boundary, single-read/EOF inputs, and the CLI binary header\n\nFixes #3554.\n\n## Root cause\n\n`content_inspector` checks up to 1024 bytes for a NUL byte, but bat passed only the first line. Random or encrypted data can contain a newline before its first NUL byte, so the shortened sample was classified as UTF-8 and binary bytes were sent to the terminal.\n\nThe fix snapshots the already-buffered prefix with `BufRead::fill_buf()` before `read_until` splits out the first line. The snapshot is non-consuming, so no bytes are lost or reordered, and it does not add a post-line blocking read. Empty input is handled without requesting a second EOF event.\n\n## Compatibility\n\nBOM detection still takes precedence, so UTF-16 input handling is unchanged. ZIP signature detection is also unchanged.\n\nPR #3763 changes the same input initialization path for a distinct issue (#2262: bounding reads for newline-free binary files). If it merges first, this PR will need a small rebase, but the behaviors are complementary.\n\n## Validation\n\n- `cargo test --all-targets --all-features` — clean run: 455 passed, 5 ignored\n- `cargo clippy --all-targets --all-features -- -D warnings`\n- `cargo fmt --check`\n- `git diff --check`\n\nDetect binary content beyond the first line\n\nAdd changelog entry for #3877\n\nMerge branch 'master' into fix-binary-detection-across-lines-3554"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "6ab6f99aac9428f1acc0e21871e86f12a1e5384e", "candidate_corpus": {"base_commit": "6ab6f99aac9428f1acc0e21871e86f12a1e5384e", "type": "repo_at_base_commit"}, "gold": {"files": ["examples/request-id/Cargo.toml"], "given_files": ["examples/request-id/src/main.rs"]}, "id": "910f104ac31c70440f6791e0", "metadata": {"changed_files": ["examples/request-id/Cargo.toml", "examples/request-id/src/main.rs"], "created_at": "2026-08-15T05:25:15Z", "fix_commit": "97def9590aaea9c70f8156f2438d1da6ebcfaf68", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "examples/request-id/Cargo.toml", "signals": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"examples/request-id/Cargo.toml": ["cargo", "examples", "request"]}}, "merged_at": "2026-08-15T08:40:51Z", "pr": 3865, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"], "source_pr": "https://github.com/tokio-rs/axum/pull/3865"}, "query": {"anchor_diff": "@@ -4,22 +4,16 @@\n //! cargo run -p example-request-id\n //! ```\n \n-use axum::{\n- http::{HeaderName, Request},\n- response::Html,\n- routing::get,\n- Router,\n-};\n+use axum::{http::Request, response::Html, routing::get, Router};\n use tower::ServiceBuilder;\n use tower_http::{\n- request_id::{MakeRequestUuid, PropagateRequestIdLayer, SetRequestIdLayer},\n+ request_id::{MakeRequestUuid, RequestId},\n trace::TraceLayer,\n+ ServiceBuilderExt,\n };\n-use tracing::{error, info, info_span};\n+use tracing::{info, info_span};\n use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};\n \n-const REQUEST_ID_HEADER: &str = \"x-request-id\";\n-\n #[tokio::main]\n async fn main() {\n tracing_subscriber::registry()\n@@ -37,32 +31,21 @@ async fn main() {\n .with(tracing_subscriber::fmt::layer())\n .init();\n \n- let x_request_id = HeaderName::from_static(REQUEST_ID_HEADER);\n-\n let middleware = ServiceBuilder::new()\n- .layer(SetRequestIdLayer::new(\n- x_request_id.clone(),\n- MakeRequestUuid,\n- ))\n+ .set_x_request_id(MakeRequestUuid)\n .layer(\n TraceLayer::new_for_http().make_span_with(|request: &Request<_>| {\n // Log the request id as generated.\n- let request_id = request.headers().get(REQUEST_ID_HEADER);\n+ let request_id = request.extensions().get::().unwrap();\n \n- match request_id {\n- Some(request_id) => info_span!(\n- \"http_request\",\n- request_id = ?request_id,\n- ),\n- None => {\n- error!(\"could not extract request_id\");\n- info_span!(\"http_request\")\n- }\n+ match request_id.header_value().to_str() {\n+ Ok(request_id) => info_span!(\"http_request\", request_id),\n+ Err(_) => info_span!(\"http_request\", request_id = ?request_id),\n }\n }),\n )\n // send headers from request to response headers\n- .layer(PropagateRequestIdLayer::new(x_request_id));\n+ .propagate_x_request_id();\n \n // build our application with a route\n let app = Router::new().route(\"/\", get(handler)).layer(middleware);", "anchor_file": "examples/request-id/src/main.rs", "intent": "examples: Refactor request-id example\n\nexamples: Get request id from extensions\n\nexamples: Use tower_http::ServiceBuilderExt to build request id middleware"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "835bd2a756b133531a8c49cb2b519654d57ace60", "candidate_corpus": {"base_commit": "835bd2a756b133531a8c49cb2b519654d57ace60", "type": "repo_at_base_commit"}, "gold": {"files": ["tests/integration_tests.rs"], "given_files": ["src/assets.rs"]}, "id": "4204fc1d095f27005d2d7db7", "metadata": {"changed_files": ["CHANGELOG.md", "src/assets.rs", "tests/examples/regression_tests/issue_2745.txt", "tests/integration_tests.rs"], "created_at": "2026-06-30T19:15:58Z", "fix_commit": "bb4f48a124b8a9eb83c9368361ed4b9a9351fe9c", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 34, "deletions": 0, "is_test": true, "path": "tests/integration_tests.rs", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": [], "nonfatal_hits": {}}, "merged_at": "2026-06-30T21:40:18Z", "pr": 3816, "ripple_relation": ["shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/sharkdp/bat/pull/3816"}, "query": {"anchor_diff": "@@ -347,15 +347,15 @@ impl HighlightingAssets {\n file_name: &OsStr,\n ignored_suffixes: &IgnoredSuffixes,\n ) -> Result>> {\n- let mut syntax = self.find_syntax_by_extension(Path::new(file_name).extension())?;\n- if syntax.is_none() {\n- syntax =\n- ignored_suffixes.try_with_stripped_suffix(file_name, |stripped_file_name| {\n- // Note: recursion\n- self.get_syntax_for_file_extension(stripped_file_name, ignored_suffixes)\n- })?;\n+ let stripped =\n+ ignored_suffixes.try_with_stripped_suffix(file_name, |stripped_file_name| {\n+ self.get_syntax_for_file_extension(stripped_file_name, ignored_suffixes)\n+ .map(Some)\n+ })?;\n+ match stripped {\n+ Some(syntax) => Ok(syntax),\n+ None => self.find_syntax_by_extension(Path::new(file_name).extension()),\n }\n- Ok(syntax)\n }\n \n fn get_first_line_syntax(\n@@ -686,6 +686,48 @@ mod tests {\n );\n }\n \n+ #[test]\n+ fn syntax_detection_ignored_suffix_falls_back_to_first_line() {\n+ let mut test = SyntaxDetectionTest::new();\n+\n+ // By default a `.txt` file uses Plain Text, even with a shebang: the\n+ // `.txt` extension wins and first-line detection is not reached.\n+ assert_eq!(\n+ test.syntax_for_file_with_content(\"test.txt\", \"#!/usr/bin/env bash\"),\n+ \"Plain Text\"\n+ );\n+\n+ // Once `.txt` is an ignored suffix it is stripped before detection. The\n+ // stripped name (`test`) has no extension, so detection falls back to the\n+ // first line -- even though `.txt` is itself a registered extension that\n+ // would otherwise match as Plain Text. See #2745.\n+ test.syntax_mapping.insert_ignored_suffix(\".txt\");\n+ assert_eq!(\n+ test.syntax_for_file_with_content(\"test.txt\", \"#!/usr/bin/env bash\"),\n+ \"Bourne Again Shell (bash)\"\n+ );\n+ assert_eq!(\n+ test.syntax_for_file_with_content(\"test.txt\", \" Plain Text match here.\n+ assert_eq!(\n+ test.syntax_for_file_with_content(\"notes.txt\", \"just some prose\"),\n+ \"!no syntax!\"\n+ );\n+\n+ // Stripping that exposes a real extension still works: `.dev` is ignored,\n+ // and the remaining `.json` extension is detected as usual.\n+ test.syntax_mapping.insert_ignored_suffix(\".dev\");\n+ assert_eq!(\n+ test.syntax_for_file_with_content(\"config.json.dev\", \"\"),\n+ \"JSON\"\n+ );\n+ }\n+\n #[test]\n fn syntax_detection_is_case_insensitive() {\n let mut test = SyntaxDetectionTest::new();", "anchor_file": "src/assets.rs", "intent": "Fix --ignored-suffix to fall back to first-line detection\n\nWhen an ignored suffix is also a registered extension (e.g. `.txt` maps to \"Plain Text\"), `get_syntax_for_file_extension` matched the raw extension before attempting the suffix strip. As a result `--ignored-suffix .txt` had no effect on such files and first-line/shebang detection was never reached, so a shell script saved as `*.txt` stayed unhighlighted.\n\nStrip ignored suffixes first and detect on the remainder; only fall back to the raw extension when no ignored suffix applies. When a suffix is stripped but the remainder has no syntax, return `None` so the caller can use first-line detection. Default behavior (no `--ignored-suffix`) is unchanged.\n\nSee #2745.\n\nFix --ignored-suffix to fall back to first-line detection"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "e1f5f5eaa7ed3aca1a9420cc4b2f759b5893a9fc", "candidate_corpus": {"base_commit": "e1f5f5eaa7ed3aca1a9420cc4b2f759b5893a9fc", "type": "repo_at_base_commit"}, "gold": {"files": ["axum/Cargo.toml"], "given_files": ["axum/src/serve/listener.rs"]}, "id": "e88af215ebaa14921e706921", "metadata": {"changed_files": ["axum/Cargo.toml", "axum/src/serve/listener.rs"], "created_at": "2026-05-31T02:50:13Z", "fix_commit": "42d6fdc80d8933ced5ff4ae858f43a3581106c75", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 6, "deletions": 2, "is_test": false, "path": "axum/Cargo.toml", "signals": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"axum/Cargo.toml": ["cargo", "axum"]}}, "merged_at": "2026-06-10T13:24:30Z", "pr": 3784, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "shared_config_or_schema"], "source_pr": "https://github.com/tokio-rs/axum/pull/3784"}, "query": {"anchor_diff": "@@ -4,13 +4,11 @@ use std::{\n pin::Pin,\n sync::Arc,\n task::{Context, Poll},\n- time::Duration,\n };\n \n use pin_project_lite::pin_project;\n use tokio::{\n io::{self, AsyncRead, AsyncWrite},\n- net::{TcpListener, TcpStream},\n sync::{OwnedSemaphorePermit, Semaphore},\n };\n \n@@ -32,8 +30,9 @@ pub trait Listener: Send + 'static {\n fn local_addr(&self) -> io::Result;\n }\n \n-impl Listener for TcpListener {\n- type Io = TcpStream;\n+#[cfg(not(target_arch = \"wasm32\"))]\n+impl Listener for tokio::net::TcpListener {\n+ type Io = tokio::net::TcpStream;\n type Addr = std::net::SocketAddr;\n \n async fn accept(&mut self) -> (Self::Io, Self::Addr) {\n@@ -242,6 +241,7 @@ where\n }\n }\n \n+#[cfg(not(target_arch = \"wasm32\"))]\n async fn handle_accept_error(e: io::Error) {\n if is_connection_error(&e) {\n return;\n@@ -259,9 +259,10 @@ async fn handle_accept_error(e: io::Error) {\n //\n // hyper allowed customizing this but axum does not.\n error!(\"accept error: {e}\");\n- tokio::time::sleep(Duration::from_secs(1)).await;\n+ tokio::time::sleep(std::time::Duration::from_secs(1)).await;\n }\n \n+#[cfg(not(target_arch = \"wasm32\"))]\n fn is_connection_error(e: &io::Error) -> bool {\n matches!(\n e.kind(),", "anchor_file": "axum/src/serve/listener.rs", "intent": "Exclude tokio/net for WASM builds\n\n## Motivation\n\nI want to implement a custom `axum::serve::Listener` for my WASM runtime, but `axum::serve` needlessly relies on tokio/net, which doesn't compile on WASM.\n\n## Solution\n\nMade tokio/net an optional feature.\n\nMake tokio/net an optional feature\n\nDocument tokio-net feature\n\nFix unused function warnings\n\nSwitching to platform-specific dependencies\n\nRemove tokio-net rustdoc\n\nAppease cargo-sort\n\nRemove redundant tokio feature annotation\n\nOops!"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "49117ced6648a432d85951f72dce777038f6ce09", "candidate_corpus": {"base_commit": "49117ced6648a432d85951f72dce777038f6ce09", "type": "repo_at_base_commit"}, "gold": {"files": ["rich/console.py", "tests/test_console.py"], "given_files": ["rich/diagnose.py"]}, "id": "1228239a1bdbb98a37b59dc9", "metadata": {"changed_files": ["CHANGELOG.md", "docs/source/console.rst", "rich/console.py", "rich/diagnose.py", "tests/test_console.py"], "created_at": "2025-06-20T20:24:13Z", "fix_commit": "3b70db5a2997de191f7db3e422dbe4da35ca1c95", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 11, "deletions": 1, "is_test": false, "path": "rich/console.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 25, "deletions": 0, "is_test": true, "path": "tests/test_console.py", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"rich/console.py": ["rich"]}}, "merged_at": "2025-06-23T16:02:53Z", "pr": 3777, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/Textualize/rich/pull/3777"}, "query": {"anchor_diff": "@@ -26,6 +26,7 @@ def report() -> None: # pragma: no cover\n \"TERM_PROGRAM\",\n \"TERM\",\n \"TTY_COMPATIBLE\",\n+ \"TTY_INTERACTIVE\",\n \"VSCODE_VERBOSE_LOGGING\",\n )\n env = {name: os.getenv(name) for name in env_names}", "anchor_file": "rich/diagnose.py", "intent": "TTY_INTERACTIVE env var\n\nAdds a `TTY_INTERACTIVE` to disable things like progress bar / status spinners in CI\n\nThis adds to the new `TTY_COMPATIBLE` which enables styles even when the file is not technically a tty, as is the case in Github Actions. `TTY_INTERACTIVE=0` will remove superfluous animations and progress bars in the CI output.\n\nTTY_INTERACTIVE env var\n\nchangelog\n\ntext\n\ntypo"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "49117ced6648a432d85951f72dce777038f6ce09", "candidate_corpus": {"base_commit": "49117ced6648a432d85951f72dce777038f6ce09", "type": "repo_at_base_commit"}, "gold": {"files": ["rich/diagnose.py", "tests/test_console.py"], "given_files": ["rich/console.py"]}, "id": "8bfcb4eae0557631d099350d", "metadata": {"changed_files": ["CHANGELOG.md", "docs/source/console.rst", "rich/console.py", "rich/diagnose.py", "tests/test_console.py"], "created_at": "2025-06-20T20:24:13Z", "fix_commit": "3b70db5a2997de191f7db3e422dbe4da35ca1c95", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 1, "deletions": 0, "is_test": false, "path": "rich/diagnose.py", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 25, "deletions": 0, "is_test": true, "path": "tests/test_console.py", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"rich/diagnose.py": ["rich"], "tests/test_console.py": ["console"]}}, "merged_at": "2025-06-23T16:02:53Z", "pr": 3777, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "gold_diff_mentions_anchor_module", "optional_test_ripple"], "source_pr": "https://github.com/Textualize/rich/pull/3777"}, "query": {"anchor_diff": "@@ -22,18 +22,20 @@ from typing import (\n Dict,\n Iterable,\n List,\n+ Literal,\n Mapping,\n NamedTuple,\n Optional,\n+ Protocol,\n TextIO,\n Tuple,\n Type,\n Union,\n cast,\n+ runtime_checkable,\n )\n \n from rich._null_file import NULL_FILE\n-from typing import Literal, Protocol, runtime_checkable\n \n from . import errors, themes\n from ._emoji_replace import _emoji_replace\n@@ -731,6 +733,14 @@ class Console:\n if no_color is not None\n else self._environ.get(\"NO_COLOR\", \"\") != \"\"\n )\n+ if force_interactive is None:\n+ tty_interactive = self._environ.get(\"TTY_INTERACTIVE\", None)\n+ if tty_interactive is not None:\n+ if tty_interactive == \"0\":\n+ force_interactive = False\n+ elif tty_interactive == \"1\":\n+ force_interactive = True\n+\n self.is_interactive = (\n (self.is_terminal and not self.is_dumb_terminal)\n if force_interactive is None", "anchor_file": "rich/console.py", "intent": "TTY_INTERACTIVE env var\n\nAdds a `TTY_INTERACTIVE` to disable things like progress bar / status spinners in CI\n\nThis adds to the new `TTY_COMPATIBLE` which enables styles even when the file is not technically a tty, as is the case in Github Actions. `TTY_INTERACTIVE=0` will remove superfluous animations and progress bars in the CI output.\n\nTTY_INTERACTIVE env var\n\nchangelog\n\ntext\n\ntypo"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "600e762b30dba5d1b9e253fabd36d0d23333e5d5", "candidate_corpus": {"base_commit": "600e762b30dba5d1b9e253fabd36d0d23333e5d5", "type": "repo_at_base_commit"}, "gold": {"files": ["axum-extra/src/response/file_stream.rs", "axum-extra/src/response/mod.rs", "axum-extra/src/response/content_disposition.rs", "axum-extra/src/response/multiple.rs"], "given_files": ["axum-extra/src/response/attachment.rs"]}, "id": "a5c2674ec36107af5117f293", "metadata": {"changed_files": ["axum-extra/CHANGELOG.md", "axum-extra/src/response/attachment.rs", "axum-extra/src/response/content_disposition.rs", "axum-extra/src/response/file_stream.rs", "axum-extra/src/response/mod.rs", "axum-extra/src/response/multiple.rs"], "created_at": "2026-05-22T23:47:06Z", "fix_commit": "b90b8e02d0f761ce36a13610acd2afa60984a5e2", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "axum-extra/src/response/file_stream.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 1, "deletions": 1, "is_test": false, "path": "axum-extra/src/response/mod.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 17, "deletions": 5, "is_test": false, "path": "axum-extra/src/response/content_disposition.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 63, "deletions": 6, "is_test": false, "path": "axum-extra/src/response/multiple.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"axum-extra/src/response/content_disposition.rs": ["content_disposition", "axum", "content", "disposition", "extra", "response"], "axum-extra/src/response/file_stream.rs": ["axum", "extra", "response", "stream"], "axum-extra/src/response/mod.rs": ["axum", "extra", "response"], "axum-extra/src/response/multiple.rs": ["axum", "extra", "response"]}}, "merged_at": "2026-06-29T09:26:48Z", "pr": 3776, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/tokio-rs/axum/pull/3776"}, "query": {"anchor_diff": "@@ -1,4 +1,4 @@\n-use super::content_disposition::EscapedFilename;\n+use super::content_disposition::EscapedQuotedString;\n use axum_core::response::IntoResponse;\n use http::{header, HeaderMap, HeaderValue};\n use tracing::error;\n@@ -91,7 +91,10 @@ where\n let filename_str = filename\n .to_str()\n .expect(\"This was a HeaderValue so this can not fail\");\n- let value = format!(\"attachment; filename=\\\"{}\\\"\", EscapedFilename(filename_str));\n+ let value = format!(\n+ \"attachment; filename=\\\"{}\\\"\",\n+ EscapedQuotedString(filename_str)\n+ );\n HeaderValue::try_from(value).expect(\"This was a HeaderValue so this can not fail\")\n } else {\n HeaderValue::from_static(\"attachment\")", "anchor_file": "axum-extra/src/response/attachment.rs", "intent": "fix(axum-extra): escape multipart Content-Disposition params\n\nCloses #3775\n\n## Summary\n\n- reuse the internal `Content-Disposition` quoted-string escaping helper for `MultipartForm`\n- reject CR/LF in multipart field names and filenames instead of serializing malformed part headers\n- add regression tests for quoted-parameter escaping and invalid multipart metadata\n\n## Root cause\n\n`MultipartForm` serialized `Part::name` and `Part::filename` directly into the part `Content-Disposition` header without escaping or newline validation. That left multipart responses out of line with the earlier `Attachment` / `FileStream` fix and allowed malformed parameter structure to be emitted into the multipart body.\n\n## Testing\n\n- `cargo test -p axum-extra --features \"multipart attachment file-stream\"`\n- `cargo check -p axum-extra --no-default-features --features multipart`\n- `cargo check -p axum-extra --no-default-features --features \"attachment file-stream\"`\n\nfix: escape multipart content-disposition params\n\nfix: satisfy clippy let-else lint\n\ndocs: add axum-extra changelog entry"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "600e762b30dba5d1b9e253fabd36d0d23333e5d5", "candidate_corpus": {"base_commit": "600e762b30dba5d1b9e253fabd36d0d23333e5d5", "type": "repo_at_base_commit"}, "gold": {"files": ["axum-extra/src/response/file_stream.rs", "axum-extra/src/response/mod.rs", "axum-extra/src/response/attachment.rs", "axum-extra/src/response/multiple.rs"], "given_files": ["axum-extra/src/response/content_disposition.rs"]}, "id": "c077dabefc229ef29d8ccef4", "metadata": {"changed_files": ["axum-extra/CHANGELOG.md", "axum-extra/src/response/attachment.rs", "axum-extra/src/response/content_disposition.rs", "axum-extra/src/response/file_stream.rs", "axum-extra/src/response/mod.rs", "axum-extra/src/response/multiple.rs"], "created_at": "2026-05-22T23:47:06Z", "fix_commit": "b90b8e02d0f761ce36a13610acd2afa60984a5e2", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "axum-extra/src/response/file_stream.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 1, "deletions": 1, "is_test": false, "path": "axum-extra/src/response/mod.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 5, "deletions": 2, "is_test": false, "path": "axum-extra/src/response/attachment.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 63, "deletions": 6, "is_test": false, "path": "axum-extra/src/response/multiple.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"axum-extra/src/response/attachment.rs": ["attachment", "axum", "extra", "response"], "axum-extra/src/response/file_stream.rs": ["axum", "extra", "response", "stream"], "axum-extra/src/response/mod.rs": ["mod", "axum", "extra", "response"], "axum-extra/src/response/multiple.rs": ["axum", "extra", "response"]}}, "merged_at": "2026-06-29T09:26:48Z", "pr": 3776, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/tokio-rs/axum/pull/3776"}, "query": {"anchor_diff": "@@ -5,9 +5,9 @@ use std::fmt::{self, Write};\n ///\n /// This prevents Content-Disposition header parameter injection\n /// (similar to CVE-2023-29401).\n-pub(crate) struct EscapedFilename<'a>(pub &'a str);\n+pub(crate) struct EscapedQuotedString<'a>(pub &'a str);\n \n-impl fmt::Display for EscapedFilename<'_> {\n+impl fmt::Display for EscapedQuotedString<'_> {\n fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n for c in self.0.chars() {\n if c == '\\\\' || c == '\"' {\n@@ -19,19 +19,24 @@ impl fmt::Display for EscapedFilename<'_> {\n }\n }\n \n+#[cfg(any(feature = \"multipart\", test))]\n+pub(crate) fn contains_newlines(value: &str) -> bool {\n+ value.contains(['\\r', '\\n'])\n+}\n+\n #[cfg(test)]\n mod tests {\n use super::*;\n \n #[test]\n fn no_special_characters() {\n- assert_eq!(EscapedFilename(\"report.pdf\").to_string(), \"report.pdf\");\n+ assert_eq!(EscapedQuotedString(\"report.pdf\").to_string(), \"report.pdf\");\n }\n \n #[test]\n fn escapes_double_quotes() {\n assert_eq!(\n- EscapedFilename(\"evil\\\"; filename*=UTF-8''pwned.txt; x=\\\"\").to_string(),\n+ EscapedQuotedString(\"evil\\\"; filename*=UTF-8''pwned.txt; x=\\\"\").to_string(),\n \"evil\\\\\\\"; filename*=UTF-8''pwned.txt; x=\\\\\\\"\",\n );\n }\n@@ -39,8 +44,15 @@ mod tests {\n #[test]\n fn escapes_backslashes() {\n assert_eq!(\n- EscapedFilename(\"file\\\\name.txt\").to_string(),\n+ EscapedQuotedString(\"file\\\\name.txt\").to_string(),\n \"file\\\\\\\\name.txt\",\n );\n }\n+\n+ #[test]\n+ fn detects_newlines() {\n+ assert!(contains_newlines(\"line\\r\\nbreak\"));\n+ assert!(contains_newlines(\"line\\nbreak\"));\n+ assert!(!contains_newlines(\"report.pdf\"));\n+ }\n }", "anchor_file": "axum-extra/src/response/content_disposition.rs", "intent": "fix(axum-extra): escape multipart Content-Disposition params\n\nCloses #3775\n\n## Summary\n\n- reuse the internal `Content-Disposition` quoted-string escaping helper for `MultipartForm`\n- reject CR/LF in multipart field names and filenames instead of serializing malformed part headers\n- add regression tests for quoted-parameter escaping and invalid multipart metadata\n\n## Root cause\n\n`MultipartForm` serialized `Part::name` and `Part::filename` directly into the part `Content-Disposition` header without escaping or newline validation. That left multipart responses out of line with the earlier `Attachment` / `FileStream` fix and allowed malformed parameter structure to be emitted into the multipart body.\n\n## Testing\n\n- `cargo test -p axum-extra --features \"multipart attachment file-stream\"`\n- `cargo check -p axum-extra --no-default-features --features multipart`\n- `cargo check -p axum-extra --no-default-features --features \"attachment file-stream\"`\n\nfix: escape multipart content-disposition params\n\nfix: satisfy clippy let-else lint\n\ndocs: add axum-extra changelog entry"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "7a37cdd00a7307954999b75d467e6f404ff6e4e0", "candidate_corpus": {"base_commit": "7a37cdd00a7307954999b75d467e6f404ff6e4e0", "type": "repo_at_base_commit"}, "gold": {"files": ["examples/static-file-server/Cargo.toml"], "given_files": ["examples/static-file-server/src/main.rs"]}, "id": "22b3b43133b33c968e5a7630", "metadata": {"changed_files": ["examples/Cargo.lock", "examples/static-file-server/Cargo.toml", "examples/static-file-server/src/main.rs", "examples/static-file-server/src/tests.rs"], "created_at": "2026-05-16T18:36:12Z", "fix_commit": "a480d71f6d55cef84f273e5a5e0563d5354ab328", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 4, "deletions": 1, "is_test": false, "path": "examples/static-file-server/Cargo.toml", "signals": ["path_token_overlap", "shared_config_or_schema"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"examples/static-file-server/Cargo.toml": ["examples", "server", "static"]}}, "merged_at": "2026-05-16T20:54:24Z", "pr": 3762, "ripple_relation": ["path_token_overlap", "shared_config_or_schema"], "source_pr": "https://github.com/tokio-rs/axum/pull/3762"}, "query": {"anchor_diff": "@@ -11,6 +11,7 @@ use std::net::SocketAddr;\n use tower::ServiceExt;\n use tower_http::{\n services::{ServeDir, ServeFile},\n+ set_status::SetStatus,\n trace::TraceLayer,\n };\n use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};\n@@ -45,13 +46,18 @@ fn using_serve_dir() -> Router {\n fn using_serve_dir_with_assets_fallback() -> Router {\n // `ServeDir` allows setting a fallback if an asset is not found\n // so with this `GET /assets/doesnt-exist.jpg` will return `index.html`\n- // rather than a 404\n- let serve_dir = ServeDir::new(\"assets\").not_found_service(ServeFile::new(\"assets/index.html\"));\n+ // rather than a 404.\n+ // The `fallback_service` ensures that all other paths (the standard\n+ // SPA pattern) also return `index.html`. We wrap it in `SetStatus` so\n+ // the response uses 404 instead of 200 -- the path wasn't found, the SPA\n+ // just handles routing client-side.\n+ let index_html = SetStatus::new(ServeFile::new(\"assets/index.html\"), StatusCode::NOT_FOUND);\n+ let serve_dir = ServeDir::new(\"assets\").not_found_service(index_html.clone());\n \n Router::new()\n .route(\"/foo\", get(|| async { \"Hi from /foo\" }))\n- .nest_service(\"/assets\", serve_dir.clone())\n- .fallback_service(serve_dir)\n+ .nest_service(\"/assets\", serve_dir)\n+ .fallback_service(index_html)\n }\n \n fn using_serve_dir_only_from_root_via_fallback() -> Router {\n@@ -107,6 +113,9 @@ fn using_serve_file_from_a_route() -> Router {\n Router::new().route_service(\"/foo\", ServeFile::new(\"assets/index.html\"))\n }\n \n+#[cfg(test)]\n+mod tests;\n+\n async fn serve(app: Router, port: u16) {\n let addr = SocketAddr::from(([127, 0, 0, 1], port));\n let listener = tokio::net::TcpListener::bind(addr).await.unwrap();", "anchor_file": "examples/static-file-server/src/main.rs", "intent": "examples: fix `using_serve_dir_with_assets_fallback` to not expose assets at root\n\nCloses #2809.\nCredit to @tobx, who identified the root cause and expected behavior in the issue thread. This is the implementation.\n\n## Motivation\n\nThe SPA example in `using_serve_dir_with_assets_fallback` is supposed to serve assets at `/assets/*` and return `index.html` for everything else. In practice, the router fallback pointed at the full `ServeDir`, so `/script.js` served the actual script rather than the index page.\n\n## Solution\n\nChange the fallback from `ServeDir` to a `ServeFile` for `index.html`. The `/assets` route is unchanged. Files still load from there, and missing ones fall back to `index.html`. Only the root-level fallback changes.\n\n`ServeFile: Clone`, so both uses share one binding instead of two identical constructor calls.\n\nAdds a regression test: `GET /script.js` returns `index.html` content, not the script.\n\nfix(examples): SPA fallback serves only index.html, not full assets dir\n\nexamples: extract index_html in using_serve_dir_with_assets_fallback\n\nexamples: remove historical comment from assets_not_served_at_root test\n\nexamples: use SetStatus to return 404 for SPA fallback"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "a480d71f6d55cef84f273e5a5e0563d5354ab328", "candidate_corpus": {"base_commit": "a480d71f6d55cef84f273e5a5e0563d5354ab328", "type": "repo_at_base_commit"}, "gold": {"files": ["axum-macros/src/lib.rs"], "given_files": ["axum-macros/src/from_request/mod.rs"]}, "id": "41b6619307210845961074d7", "metadata": {"changed_files": ["axum-macros/CHANGELOG.md", "axum-macros/src/from_request/mod.rs", "axum-macros/src/lib.rs", "axum-macros/tests/from_request/fail/option_without_optional_from_request.rs", "axum-macros/tests/from_request/fail/option_without_optional_from_request.stderr", "axum-macros/tests/from_request/pass/option_via_json.rs", "axum-macros/tests/from_request/pass/option_via_parts.rs"], "created_at": "2026-05-15T18:54:13Z", "fix_commit": "6ed9210351633ed2c420dc051dc0a13b73744dfe", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "axum-macros/src/lib.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"axum-macros/src/lib.rs": ["axum", "macros"]}}, "merged_at": "2026-05-16T21:33:44Z", "pr": 3760, "ripple_relation": ["path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/tokio-rs/axum/pull/3760"}, "query": {"anchor_diff": "@@ -476,19 +476,25 @@ fn extract_fields(\n \n if peel_option(&field.ty).is_some() {\n let field_ty = into_outer(via.as_ref(), ty_span, peel_option(&field.ty).unwrap());\n+ let map_err = if let Some(rejection) = rejection {\n+ quote! { <#rejection as ::std::convert::From<_>>::from }\n+ } else {\n+ quote! { ::axum::response::IntoResponse::into_response }\n+ };\n+\n let tokens = match tr {\n Trait::FromRequest => {\n quote_spanned! {ty_span=>\n #member: {\n let (mut parts, body) = req.into_parts();\n let value =\n- <#field_ty as ::axum::extract::FromRequestParts<_>>::from_request_parts(\n+ <#field_ty as ::axum::extract::OptionalFromRequestParts<_>>::from_request_parts(\n &mut parts,\n state,\n )\n .await\n- .ok()\n- .map(#into_inner);\n+ .map(|opt| opt.map(#into_inner))\n+ .map_err(#map_err)?;\n req = ::axum::http::Request::from_parts(parts, body);\n value\n },\n@@ -497,13 +503,13 @@ fn extract_fields(\n Trait::FromRequestParts => {\n quote_spanned! {ty_span=>\n #member: {\n- <#field_ty as ::axum::extract::FromRequestParts<_>>::from_request_parts(\n+ <#field_ty as ::axum::extract::OptionalFromRequestParts<_>>::from_request_parts(\n parts,\n state,\n )\n .await\n- .ok()\n- .map(#into_inner)\n+ .map(|opt| opt.map(#into_inner))\n+ .map_err(#map_err)?\n },\n }\n }\n@@ -597,12 +603,18 @@ fn extract_fields(\n \n let item = if peel_option(&field.ty).is_some() {\n let field_ty = into_outer(via.as_ref(), ty_span, peel_option(&field.ty).unwrap());\n+ let map_err = if let Some(rejection) = rejection {\n+ quote! { <#rejection as ::std::convert::From<_>>::from }\n+ } else {\n+ quote! { ::axum::response::IntoResponse::into_response }\n+ };\n+\n quote_spanned! {ty_span=>\n #member: {\n- <#field_ty as ::axum::extract::FromRequest<_, _>>::from_request(req, state)\n+ <#field_ty as ::axum::extract::OptionalFromRequest<_, _>>::from_request(req, state)\n .await\n- .ok()\n- .map(#into_inner)\n+ .map(|opt| opt.map(#into_inner))\n+ .map_err(#map_err)?\n },\n }\n } else if peel_result_ok(&field.ty).is_some() {", "anchor_file": "axum-macros/src/from_request/mod.rs", "intent": "fix(axum-macros): use OptionalFromRequest for Option fields\n\nThis supersedes #3665 and closes #3623 by implementing proper rejection mapping using OptionalFromRequest/OptionalFromRequestParts and adding regression tests for JSON parsing errors.\n\n\n\n## Motivation\n\nCurrently, Option fields in #[derive(FromRequest)] and #[derive(FromRequestParts)] use .ok() to handle the extracted result. This approach silently swallows all rejections (such as a JsonRejection when a payload is malformed or invalid) and converts them into None. The expected behavior is that an invalid payload should properly propagate its rejection to the client, and None should only be returned when the payload or part is genuinely missing (relying on the extractor's specific optional semantics).\n\n## Solution\n\nReplaced the .ok() chaining for Option fields with the OptionalFromRequest and OptionalFromRequestParts traits. This delegates the decision of when to return None versus when to propagate a rejection directly to the specific extractor's implementation.\n\nAdditionally, added two regression tests (option_via_json.rs and option_via_parts.rs) to ensure that missing data gracefully resolves to None, while malformed data (like invalid JSON) properly surfaces the correct rejection/HTTP error.\n\nfix(axum-macros): use OptionalFromRequest for Option fields\n\nfix(test): use axum 0.7 route syntax /{something} instead of /:something\n\ntest: add failing test for Option without OptionalFromRequest\n\nMerge branch 'main' into fix/optional-from-request-3623"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "a480d71f6d55cef84f273e5a5e0563d5354ab328", "candidate_corpus": {"base_commit": "a480d71f6d55cef84f273e5a5e0563d5354ab328", "type": "repo_at_base_commit"}, "gold": {"files": ["axum-macros/src/from_request/mod.rs"], "given_files": ["axum-macros/src/lib.rs"]}, "id": "d64811af619813885a151b4d", "metadata": {"changed_files": ["axum-macros/CHANGELOG.md", "axum-macros/src/from_request/mod.rs", "axum-macros/src/lib.rs", "axum-macros/tests/from_request/fail/option_without_optional_from_request.rs", "axum-macros/tests/from_request/fail/option_without_optional_from_request.stderr", "axum-macros/tests/from_request/pass/option_via_json.rs", "axum-macros/tests/from_request/pass/option_via_parts.rs"], "created_at": "2026-05-15T18:54:13Z", "fix_commit": "6ed9210351633ed2c420dc051dc0a13b73744dfe", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 21, "deletions": 9, "is_test": false, "path": "axum-macros/src/from_request/mod.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"axum-macros/src/from_request/mod.rs": ["axum", "from", "macros", "request"]}}, "merged_at": "2026-05-16T21:33:44Z", "pr": 3760, "ripple_relation": ["path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/tokio-rs/axum/pull/3760"}, "query": {"anchor_diff": "@@ -136,7 +136,7 @@ use from_request::Trait::{FromRequest, FromRequestParts};\n ///\n /// #[derive(FromRequest)]\n /// struct MyExtractor {\n-/// // This will extracted via `Option::>::from_request`\n+/// // This will extracted via ` as OptionalFromRequestParts>::from_request_parts`\n /// #[from_request(via(TypedHeader))]\n /// content_type: Option,\n /// // This will extracted via", "anchor_file": "axum-macros/src/lib.rs", "intent": "fix(axum-macros): use OptionalFromRequest for Option fields\n\nThis supersedes #3665 and closes #3623 by implementing proper rejection mapping using OptionalFromRequest/OptionalFromRequestParts and adding regression tests for JSON parsing errors.\n\n\n\n## Motivation\n\nCurrently, Option fields in #[derive(FromRequest)] and #[derive(FromRequestParts)] use .ok() to handle the extracted result. This approach silently swallows all rejections (such as a JsonRejection when a payload is malformed or invalid) and converts them into None. The expected behavior is that an invalid payload should properly propagate its rejection to the client, and None should only be returned when the payload or part is genuinely missing (relying on the extractor's specific optional semantics).\n\n## Solution\n\nReplaced the .ok() chaining for Option fields with the OptionalFromRequest and OptionalFromRequestParts traits. This delegates the decision of when to return None versus when to propagate a rejection directly to the specific extractor's implementation.\n\nAdditionally, added two regression tests (option_via_json.rs and option_via_parts.rs) to ensure that missing data gracefully resolves to None, while malformed data (like invalid JSON) properly surfaces the correct rejection/HTTP error.\n\nfix(axum-macros): use OptionalFromRequest for Option fields\n\nfix(test): use axum 0.7 route syntax /{something} instead of /:something\n\ntest: add failing test for Option without OptionalFromRequest\n\nMerge branch 'main' into fix/optional-from-request-3623"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "986abe8df66f7b22582cfb54d8891abb34452aae", "candidate_corpus": {"base_commit": "986abe8df66f7b22582cfb54d8891abb34452aae", "type": "repo_at_base_commit"}, "gold": {"files": ["axum-core/src/response/into_response.rs", "axum/src/routing/route.rs"], "given_files": ["axum-core/src/body.rs"]}, "id": "120c8df9f02d1a8c871c6370", "metadata": {"changed_files": ["axum-core/CHANGELOG.md", "axum-core/src/body.rs", "axum-core/src/body/unknown.rs", "axum-core/src/response/into_response.rs", "axum/CHANGELOG.md", "axum/src/routing/route.rs"], "created_at": "2026-05-02T11:09:43Z", "fix_commit": "c2612e2839af2e162d197db6d55abdf45edc8968", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "axum-core/src/response/into_response.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 60, "deletions": 0, "is_test": false, "path": "axum/src/routing/route.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"axum-core/src/response/into_response.rs": ["axum", "response"], "axum/src/routing/route.rs": ["axum"]}}, "merged_at": "2026-05-15T08:13:48Z", "pr": 3742, "ripple_relation": ["path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/tokio-rs/axum/pull/3742"}, "query": {"anchor_diff": "@@ -1,5 +1,8 @@\n //! HTTP body utilities.\n \n+mod unknown;\n+pub(crate) use unknown::Unknown;\n+\n use crate::{BoxError, Error};\n use bytes::Bytes;\n use futures_core::{Stream, TryStream};\n@@ -53,6 +56,30 @@ impl Body {\n Self::new(http_body_util::Empty::new())\n }\n \n+ /// Create a body of unknown size.\n+ ///\n+ /// This is useful in cases where a body is required to construct a\n+ /// response, but the size of the body is not known.\n+ ///\n+ /// For example, this can be used to respond to `HEAD` requests,\n+ /// for which the body of the corresponding `GET` request would be expensive\n+ /// to compute. Note that this particular case is also mentioned in\n+ /// [RFC 9110 (Section 9.3.2, Paragraph 2)].\n+ ///\n+ /// The most notable difference compared to an empty body as returned by\n+ /// [`Body::empty`] lies in the upper bound returned by [`Body::size_hint`]:\n+ /// The upper bound of the size of an empty body is 0 bytes, while there\n+ /// is no upper bound for the size of an unknown body.\n+ ///\n+ /// Other than the size hint, an unknown body behaves like an empty body,\n+ /// i.e., [`Body::is_end_stream`] returns `true`, and when polled via\n+ /// [`Body::poll_frame`], it immediately returns `Poll::Ready(None)`.\n+ ///\n+ /// [RFC 9110 (Section 9.3.2, Paragraph 2)]: https://datatracker.ietf.org/doc/html/rfc9110#section-9.3.2-2\n+ pub fn unknown() -> Self {\n+ Self::new(Unknown::new())\n+ }\n+\n /// Create a new `Body` from a [`Stream`].\n ///\n /// [`Stream`]: https://docs.rs/futures-core/latest/futures_core/stream/trait.Stream.html", "anchor_file": "axum-core/src/body.rs", "intent": "body: Introduce Bodies of Unknown Size\n\nAs reported in , in some responses to HEAD requests, the header `content-type: 0` would be included, even though the size of the body was not known and also not zero.\n\nThe reason for this was that `axum::body::Body::empty`, which represents a body that is *known to be empty* was used, even though *nothing was known about the body*.\n\nTo remedy, introduce a new utility type `axum::body::Unknown`, which represents an unknown body. This type could be considered for upstreaming to the `http-body-util` crate in the future.\n\nbody: Introduce Bodies of Unknown Size"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "986abe8df66f7b22582cfb54d8891abb34452aae", "candidate_corpus": {"base_commit": "986abe8df66f7b22582cfb54d8891abb34452aae", "type": "repo_at_base_commit"}, "gold": {"files": ["axum-core/src/body.rs", "axum/src/routing/route.rs"], "given_files": ["axum-core/src/response/into_response.rs"]}, "id": "d5d79a2efb29d9314902f18c", "metadata": {"changed_files": ["axum-core/CHANGELOG.md", "axum-core/src/body.rs", "axum-core/src/body/unknown.rs", "axum-core/src/response/into_response.rs", "axum/CHANGELOG.md", "axum/src/routing/route.rs"], "created_at": "2026-05-02T11:09:43Z", "fix_commit": "c2612e2839af2e162d197db6d55abdf45edc8968", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 27, "deletions": 0, "is_test": false, "path": "axum-core/src/body.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}, {"additions": 60, "deletions": 0, "is_test": false, "path": "axum/src/routing/route.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"axum-core/src/body.rs": ["body", "axum"], "axum/src/routing/route.rs": ["axum"]}}, "merged_at": "2026-05-15T08:13:48Z", "pr": 3742, "ripple_relation": ["path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/tokio-rs/axum/pull/3742"}, "query": {"anchor_diff": "@@ -128,7 +128,7 @@ impl IntoResponse for StatusCode {\n \n impl IntoResponse for () {\n fn into_response(self) -> Response {\n- Body::empty().into_response()\n+ Body::unknown().into_response()\n }\n }", "anchor_file": "axum-core/src/response/into_response.rs", "intent": "body: Introduce Bodies of Unknown Size\n\nAs reported in , in some responses to HEAD requests, the header `content-type: 0` would be included, even though the size of the body was not known and also not zero.\n\nThe reason for this was that `axum::body::Body::empty`, which represents a body that is *known to be empty* was used, even though *nothing was known about the body*.\n\nTo remedy, introduce a new utility type `axum::body::Unknown`, which represents an unknown body. This type could be considered for upstreaming to the `http-body-util` crate in the future.\n\nbody: Introduce Bodies of Unknown Size"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "7be02d77545cb918ad2f6b9b62c81fe769afaab6", "candidate_corpus": {"base_commit": "7be02d77545cb918ad2f6b9b62c81fe769afaab6", "type": "repo_at_base_commit"}, "gold": {"files": ["axum-core/src/response/into_response.rs"], "given_files": ["axum-core/src/response/into_response_parts.rs"]}, "id": "9068761c1b5c9bc1d7561bbd", "metadata": {"changed_files": ["axum-core/src/response/into_response.rs", "axum-core/src/response/into_response_parts.rs", "axum-macros/tests/debug_handler/fail/single_wrong_return_tuple.stderr", "axum-macros/tests/debug_handler/fail/wrong_return_tuple.stderr", "axum-macros/tests/debug_handler/fail/wrong_return_type.stderr"], "created_at": "2026-04-12T09:12:39Z", "fix_commit": "309d1bd9530eec2217134cb262760af1df42ee3b", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 3, "deletions": 0, "is_test": false, "path": "axum-core/src/response/into_response.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"axum-core/src/response/into_response.rs": ["axum", "into", "response"]}}, "merged_at": "2026-04-15T11:06:41Z", "pr": 3723, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/tokio-rs/axum/pull/3723"}, "query": {"anchor_diff": "@@ -70,6 +70,9 @@ use std::{convert::Infallible, fmt};\n /// SetHeader(\"x-foo\", \"custom\")\n /// }\n /// ```\n+#[diagnostic::on_unimplemented(\n+ note = \"See `https://docs.rs/axum/0.8/axum/response/trait.IntoResponseParts.html` for details\"\n+)]\n pub trait IntoResponseParts {\n /// The type returned in the event of an error.\n ///", "anchor_file": "axum-core/src/response/into_response_parts.rs", "intent": "feat: add `#[diagnostic::on_unimplemented]` to `IntoResponse` and `IntoResponseParts`\n\n## Motivation\n\nThe `FromRequest`, `FromRequestParts`, and `Handler` traits already use `#[diagnostic::on_unimplemented]` to provide helpful compiler messages when users encounter trait bound errors. However, `IntoResponse` and `IntoResponseParts` — two of the most commonly encountered traits in error messages — lack this attribute.\n\nWhen users forget to implement `IntoResponse` on their custom response types (or return types that don't implement it), the compiler shows a bare \"trait bound not satisfied\" error without guidance.\n\n## Solution\n\nAdd `#[diagnostic::on_unimplemented]` to both `IntoResponse` and `IntoResponseParts` traits in `axum-core`, with links to the relevant documentation pages. This matches the existing pattern used by the extractor and handler traits.\n\nfeat: add #[diagnostic::on_unimplemented] to IntoResponse and IntoResponseParts\n\nMerge branch 'main' into feat/into-response-diagnostic"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "7be02d77545cb918ad2f6b9b62c81fe769afaab6", "candidate_corpus": {"base_commit": "7be02d77545cb918ad2f6b9b62c81fe769afaab6", "type": "repo_at_base_commit"}, "gold": {"files": ["axum-core/src/response/into_response_parts.rs"], "given_files": ["axum-core/src/response/into_response.rs"]}, "id": "d77f8cb3158cda498844f0d9", "metadata": {"changed_files": ["axum-core/src/response/into_response.rs", "axum-core/src/response/into_response_parts.rs", "axum-macros/tests/debug_handler/fail/single_wrong_return_tuple.stderr", "axum-macros/tests/debug_handler/fail/wrong_return_tuple.stderr", "axum-macros/tests/debug_handler/fail/wrong_return_type.stderr"], "created_at": "2026-04-12T09:12:39Z", "fix_commit": "309d1bd9530eec2217134cb262760af1df42ee3b", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 3, "deletions": 0, "is_test": false, "path": "axum-core/src/response/into_response_parts.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"axum-core/src/response/into_response_parts.rs": ["axum", "into", "response"]}}, "merged_at": "2026-04-15T11:06:41Z", "pr": 3723, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/tokio-rs/axum/pull/3723"}, "query": {"anchor_diff": "@@ -109,6 +109,9 @@ use std::{\n /// let app = Router::new().route(\"/\", get(|| async { MyBody }));\n /// # let _: Router = app;\n /// ```\n+#[diagnostic::on_unimplemented(\n+ note = \"See `https://docs.rs/axum/0.8/axum/response/trait.IntoResponse.html` for details\"\n+)]\n pub trait IntoResponse {\n /// Create a response.\n #[must_use]", "anchor_file": "axum-core/src/response/into_response.rs", "intent": "feat: add `#[diagnostic::on_unimplemented]` to `IntoResponse` and `IntoResponseParts`\n\n## Motivation\n\nThe `FromRequest`, `FromRequestParts`, and `Handler` traits already use `#[diagnostic::on_unimplemented]` to provide helpful compiler messages when users encounter trait bound errors. However, `IntoResponse` and `IntoResponseParts` — two of the most commonly encountered traits in error messages — lack this attribute.\n\nWhen users forget to implement `IntoResponse` on their custom response types (or return types that don't implement it), the compiler shows a bare \"trait bound not satisfied\" error without guidance.\n\n## Solution\n\nAdd `#[diagnostic::on_unimplemented]` to both `IntoResponse` and `IntoResponseParts` traits in `axum-core`, with links to the relevant documentation pages. This matches the existing pattern used by the extractor and handler traits.\n\nfeat: add #[diagnostic::on_unimplemented] to IntoResponse and IntoResponseParts\n\nMerge branch 'main' into feat/into-response-diagnostic"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "bff1764b700884250d6f0644392d6c5a2ba2c9e0", "candidate_corpus": {"base_commit": "bff1764b700884250d6f0644392d6c5a2ba2c9e0", "type": "repo_at_base_commit"}, "gold": {"files": ["axum-core/src/response/into_response_parts.rs"], "given_files": ["axum/src/response/redirect.rs"]}, "id": "0416116a3a5dfc88dfd4f402", "metadata": {"changed_files": ["axum-core/CHANGELOG.md", "axum-core/src/response/into_response_parts.rs", "axum/CHANGELOG.md", "axum/src/response/redirect.rs"], "created_at": "2026-04-12T08:46:00Z", "fix_commit": "b0123f70513e8519c4adfbfe2d0ebfd8f543cb33", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 12, "deletions": 0, "is_test": false, "path": "axum-core/src/response/into_response_parts.rs", "signals": ["path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"axum-core/src/response/into_response_parts.rs": ["into_response_parts", "axum", "parts", "response"]}}, "merged_at": "2026-05-02T15:46:22Z", "pr": 3721, "ripple_relation": ["path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/tokio-rs/axum/pull/3721"}, "query": {"anchor_diff": "@@ -1,4 +1,4 @@\n-use axum_core::response::{IntoResponse, Response};\n+use axum_core::response::{IntoResponse, IntoResponseParts, Response, ResponseParts};\n use http::{header::LOCATION, HeaderValue, StatusCode};\n \n /// Response that redirects the request to another location.\n@@ -93,11 +93,65 @@ impl IntoResponse for Redirect {\n }\n }\n \n+impl IntoResponseParts for Redirect {\n+ type Error = (StatusCode, String);\n+\n+ /// Sets the redirect status code and `Location` header on the response.\n+ ///\n+ /// This allows `Redirect` to be used as part of a response tuple, for example\n+ /// to include a body alongside a redirect as recommended by\n+ /// [RFC 9110 §15.4.4](https://datatracker.ietf.org/doc/html/rfc9110#name-303-see-other).\n+ ///\n+ /// # Examples\n+ ///\n+ /// ```rust\n+ /// use axum::response::{Html, Redirect};\n+ ///\n+ /// let url = \"https://example.com\";\n+ ///\n+ /// // Return a redirect with a body\n+ /// let response = (\n+ /// Redirect::to(url),\n+ /// Html(format!(\n+ /// r#\"

Redirecting to {url}

\"#,\n+ /// )),\n+ /// );\n+ /// ```\n+ ///\n+ /// Note that when used alongside an explicit [`StatusCode`] in a tuple, the\n+ /// `StatusCode` takes precedence:\n+ ///\n+ /// ```rust\n+ /// use axum::response::Redirect;\n+ /// use axum::http::StatusCode;\n+ ///\n+ /// // The status will be 307, not 303\n+ /// let response = (\n+ /// StatusCode::TEMPORARY_REDIRECT,\n+ /// Redirect::to(\"/new\"),\n+ /// \"redirecting...\",\n+ /// );\n+ /// ```\n+ fn into_response_parts(self, mut res: ResponseParts) -> Result {\n+ let location = HeaderValue::try_from(self.location).map_err(|err| {\n+ (\n+ StatusCode::INTERNAL_SERVER_ERROR,\n+ format!(\"invalid redirect location: {err}\"),\n+ )\n+ })?;\n+\n+ *res.status_mut() = self.status_code;\n+ res.headers_mut().insert(LOCATION, location);\n+\n+ Ok(res)\n+ }\n+}\n+\n #[cfg(test)]\n mod tests {\n use super::Redirect;\n use axum_core::response::IntoResponse;\n- use http::StatusCode;\n+ use http::{header::LOCATION, StatusCode};\n \n const EXAMPLE_URL: &str = \"https://example.com\";\n \n@@ -135,4 +189,49 @@ mod tests {\n \n assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);\n }\n+\n+ #[test]\n+ fn into_response_parts_sets_status_and_location() {\n+ let response = (Redirect::to(EXAMPLE_URL), \"body\").into_response();\n+\n+ assert_eq!(response.status(), StatusCode::SEE_OTHER);\n+ assert_eq!(response.headers().get(LOCATION).unwrap(), EXAMPLE_URL);\n+ }\n+\n+ #[test]\n+ fn into_response_parts_with_permanent_redirect() {\n+ let response = (Redirect::permanent(EXAMPLE_URL), \"body\").into_response();\n+\n+ assert_eq!(response.status(), StatusCode::PERMANENT_REDIRECT);\n+ assert_eq!(response.headers().get(LOCATION).unwrap(), EXAMPLE_URL);\n+ }\n+\n+ #[test]\n+ fn into_response_parts_with_temporary_redirect() {\n+ let response = (Redirect::temporary(EXAMPLE_URL), \"body\").into_response();\n+\n+ assert_eq!(response.status(), StatusCode::TEMPORARY_REDIRECT);\n+ assert_eq!(response.headers().get(LOCATION).unwrap(), EXAMPLE_URL);\n+ }\n+\n+ #[test]\n+ fn into_response_parts_explicit_status_overrides() {\n+ // Explicit StatusCode in a tuple takes precedence over the Redirect status\n+ let response = (\n+ StatusCode::TEMPORARY_REDIRECT,\n+ Redirect::to(EXAMPLE_URL),\n+ \"body\",\n+ )\n+ .into_response();\n+\n+ assert_eq!(response.status(), StatusCode::TEMPORARY_REDIRECT);\n+ assert_eq!(response.headers().get(LOCATION).unwrap(), EXAMPLE_URL);\n+ }\n+\n+ #[test]\n+ fn into_response_parts_invalid_location() {\n+ let response = (Redirect::permanent(\"invalid\\nlocation\"), \"body\").into_response();\n+\n+ assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);\n+ }\n }", "anchor_file": "axum/src/response/redirect.rs", "intent": "feat: impl IntoResponseParts for Redirect\n\n## What\n\nImplement `IntoResponseParts` for `Redirect`, allowing it to be used as part of a response tuple alongside a custom body.\n\n## Why\n\n[RFC 9110 §15.4.4](https://datatracker.ietf.org/doc/html/rfc9110#name-303-see-other) recommends that redirect responses (especially 303 See Other) include a short hypertext note with a hyperlink to the redirect target. Currently, achieving this requires manually constructing the response with `StatusCode` and headers:\n\n```rust\n(\n StatusCode::SEE_OTHER,\n [(header::LOCATION, url)],\n Html(format!(r#\"

Redirecting to {url}

\"#)),\n)\n```\n\nWith this change, you can simply write:\n\n```rust\n(\n Redirect::to(url),\n Html(format!(r#\"

Redirecting to {url}

\"#)),\n)\n```\n\nCloses #3637. An earlier attempt at this (#3660) was abandoned when the author deleted their account.\n\n## How\n\n**axum-core:** Added `status()` and `status_mut()` methods to `ResponseParts`. This follows the existing pattern of `headers()`/`headers_mut()` and `extensions()`/`extensions_mut()`, and is a purely additive change to the public API. This enables `IntoResponseParts` implementations to set the response status code.\n\n**axum:** Implemented `IntoResponseParts for Redirect` which:\n1. Converts the location string to a `HeaderValue` (returning a 500 error on invalid values, matching the existing `IntoResponse` behavior)\n2. Sets the status code via `status_mut()`\n3. Inserts the `Location` header\n\nWhen used alongside an explicit `StatusCode` in a tuple (e.g., `(StatusCode::TEMPORARY_REDIRECT, Redirect::to(url), body)`), the explicit `StatusCode` takes precedence — this is consistent with how the tuple `IntoResponse` impl works (status is set *after* parts are processed).\n\n## Test\n...[truncated]"}, "repo": "tokio-rs/axum", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "de2f21562a3f197cad98a6538d1886a86f67e02c", "candidate_corpus": {"base_commit": "de2f21562a3f197cad98a6538d1886a86f67e02c", "type": "repo_at_base_commit"}, "gold": {"files": ["src/input.rs"], "given_files": ["src/lessopen.rs"]}, "id": "1ebcc32c4bf8eed4fadd6d5d", "metadata": {"changed_files": ["CHANGELOG.md", "src/input.rs", "src/lessopen.rs"], "created_at": "2026-04-27T15:11:27Z", "fix_commit": "8cadefb5cbe123180538c885db4f28265fcad9fb", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 35, "deletions": 9, "is_test": false, "path": "src/input.rs", "signals": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_stem_hint"], "nonfatal_hits": {"src/input.rs": ["input"]}}, "merged_at": "2026-04-27T18:46:10Z", "pr": 3706, "ripple_relation": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol"], "source_pr": "https://github.com/sharkdp/bat/pull/3706"}, "query": {"anchor_diff": "@@ -155,7 +155,7 @@ impl LessOpenPreprocessor {\n \n Ok(OpenedInput {\n kind,\n- reader: InputReader::new(BufReader::new(\n+ reader: InputReader::try_new(BufReader::new(\n if matches!(self.kind, LessOpenKind::TempFile) {\n let lessopen_string = match String::from_utf8(lessopen_stdout) {\n Ok(string) => string,\n@@ -192,7 +192,7 @@ impl LessOpenPreprocessor {\n .map(|s| s.replacen(\"%s\", &path_str, 1).replacen(\"%s\", \"-\", 1)),\n }\n },\n- )),\n+ ))?,\n metadata: input.metadata,\n description: input.description,\n })", "anchor_file": "src/lessopen.rs", "intent": "Propagate initial input read errors\n\nCloses #3002.\n\n## What changed\n- propagate errors from the first input read instead of treating them as empty input\n- keep the existing first-line buffering behavior for successful reads\n- cover the regression with a focused input-opening test\n\n## Validation\n- cargo test input_open_returns_initial_read_errors\n- cargo test --lib input\n- cargo test lessopen\n- cargo test --all-features lessopen\n- cargo fmt -- --check\n- cargo clippy --locked --all-targets --all-features -- -D warnings\n- cargo test --locked\n- git diff --check\n\nPropagate initial input read errors"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "de2f21562a3f197cad98a6538d1886a86f67e02c", "candidate_corpus": {"base_commit": "de2f21562a3f197cad98a6538d1886a86f67e02c", "type": "repo_at_base_commit"}, "gold": {"files": ["src/lessopen.rs"], "given_files": ["src/input.rs"]}, "id": "c9e387662ef7950a47cc1fcf", "metadata": {"changed_files": ["CHANGELOG.md", "src/input.rs", "src/lessopen.rs"], "created_at": "2026-04-27T15:11:27Z", "fix_commit": "8cadefb5cbe123180538c885db4f28265fcad9fb", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 2, "deletions": 2, "is_test": false, "path": "src/lessopen.rs", "signals": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_stem_hint"], "nonfatal_hits": {"src/lessopen.rs": ["lessopen"]}}, "merged_at": "2026-04-27T18:46:10Z", "pr": 3706, "ripple_relation": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol"], "source_pr": "https://github.com/sharkdp/bat/pull/3706"}, "query": {"anchor_diff": "@@ -207,7 +207,7 @@ impl<'a> Input<'a> {\n kind: OpenedInputKind::StdIn,\n description,\n metadata: self.metadata,\n- reader: InputReader::new(stdin),\n+ reader: InputReader::try_new(stdin)?,\n })\n }\n \n@@ -236,14 +236,14 @@ impl<'a> Input<'a> {\n file = input_identifier.into_inner().expect(\"The file was lost in the clircle::Identifier, this should not have happened...\");\n }\n \n- InputReader::new(BufReader::new(file))\n+ InputReader::try_new(BufReader::new(file))?\n },\n }),\n InputKind::CustomReader(reader) => Ok(OpenedInput {\n description,\n kind: OpenedInputKind::CustomReader,\n metadata: self.metadata,\n- reader: InputReader::new(BufReader::new(reader)),\n+ reader: InputReader::try_new(BufReader::new(reader))?,\n }),\n }\n }\n@@ -257,24 +257,29 @@ pub(crate) struct InputReader<'a> {\n }\n \n impl<'a> InputReader<'a> {\n- pub(crate) fn new(mut reader: R) -> InputReader<'a> {\n+ #[cfg(test)]\n+ pub(crate) fn new(reader: R) -> InputReader<'a> {\n+ Self::try_new(reader).expect(\"reading the first line failed\")\n+ }\n+\n+ pub(crate) fn try_new(mut reader: R) -> io::Result> {\n let mut first_line = vec![];\n- reader.read_until(b'\\n', &mut first_line).ok();\n+ reader.read_until(b'\\n', &mut first_line)?;\n \n let content_type = inspect_content_type(&first_line);\n \n if content_type == Some(ContentType::UTF_16LE) {\n- read_utf16_line(&mut reader, &mut first_line, 0x00, 0x0A).ok();\n+ read_utf16_line(&mut reader, &mut first_line, 0x00, 0x0A)?;\n } else if content_type == Some(ContentType::UTF_16BE) {\n- read_utf16_line(&mut reader, &mut first_line, 0x0A, 0x00).ok();\n+ read_utf16_line(&mut reader, &mut first_line, 0x0A, 0x00)?;\n }\n \n- InputReader {\n+ Ok(InputReader {\n inner: Box::new(reader),\n first_line,\n content_type,\n unbuffered: false,\n- }\n+ })\n }\n \n pub(crate) fn read_line(&mut self, buf: &mut Vec) -> io::Result {\n@@ -405,6 +410,27 @@ fn non_zip_pk_prefix_is_not_treated_as_binary() {\n );\n }\n \n+#[test]\n+fn input_open_returns_initial_read_errors() {\n+ struct FailingRead;\n+\n+ impl Read for FailingRead {\n+ fn read(&mut self, _buf: &mut [u8]) -> io::Result {\n+ Err(io::Error::other(\"initial read failed\"))\n+ }\n+ }\n+\n+ let input = Input::from_reader(Box::new(FailingRead));\n+ let result = input.open(io::empty(), None);\n+\n+ assert!(result.is_err());\n+ assert!(result\n+ .err()\n+ .unwrap()\n+ .to_string()\n+ .contains(\"initial read failed\"));\n+}\n+\n #[test]\n fn utf16le() {\n let content = b\"\\xFF\\xFE\\x73\\x00\\x0A\\x00\\x64\\x00\";", "anchor_file": "src/input.rs", "intent": "Propagate initial input read errors\n\nCloses #3002.\n\n## What changed\n- propagate errors from the first input read instead of treating them as empty input\n- keep the existing first-line buffering behavior for successful reads\n- cover the regression with a focused input-opening test\n\n## Validation\n- cargo test input_open_returns_initial_read_errors\n- cargo test --lib input\n- cargo test lessopen\n- cargo test --all-features lessopen\n- cargo fmt -- --check\n- cargo clippy --locked --all-targets --all-features -- -D warnings\n- cargo test --locked\n- git diff --check\n\nPropagate initial input read errors"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "04576fd5a59acd3c223f042a8e9e4aaa4b1d09f1", "candidate_corpus": {"base_commit": "04576fd5a59acd3c223f042a8e9e4aaa4b1d09f1", "type": "repo_at_base_commit"}, "gold": {"files": ["Cargo.toml", "tests/tester/mod.rs"], "given_files": ["src/diff.rs"]}, "id": "1636244050ee8decd1111066", "metadata": {"changed_files": ["CHANGELOG.md", "Cargo.lock", "Cargo.toml", "src/diff.rs", "tests/tester/mod.rs"], "created_at": "2026-04-26T20:07:17Z", "fix_commit": "8f70e0cf00e1bca04df97669d5b50b9bf4608746", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 4, "deletions": 4, "is_test": false, "path": "Cargo.toml", "signals": ["gold_diff_mentions_anchor_module", "shared_changed_symbol", "shared_config_or_schema"]}, {"additions": 40, "deletions": 31, "is_test": true, "path": "tests/tester/mod.rs", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_stem_hint"], "nonfatal_hits": {"Cargo.toml": ["cargo"], "tests/tester/mod.rs": ["mod"]}}, "merged_at": "2026-06-27T02:53:22Z", "pr": 3703, "ripple_relation": ["gold_diff_mentions_anchor_module", "shared_changed_symbol", "shared_config_or_schema", "optional_test_ripple"], "source_pr": "https://github.com/sharkdp/bat/pull/3703"}, "query": {"anchor_diff": "@@ -1,12 +1,13 @@\n #![cfg(feature = \"git\")]\n \n+use gix::diff::blob::pipeline::{Mode, WorktreeRoots};\n+use gix::diff::blob::{Algorithm, HunkIter, ResourceKind};\n+use gix::object::tree::EntryKind;\n+use path_abs::PathInfo;\n use std::collections::HashMap;\n-use std::fs;\n use std::path::Path;\n \n-use git2::{DiffOptions, IntoCString, Repository};\n-\n-#[derive(Copy, Clone, Debug)]\n+#[derive(Copy, Clone, Debug, PartialEq, Eq)]\n pub enum LineChange {\n Added,\n RemovedAbove,\n@@ -16,68 +17,181 @@ pub enum LineChange {\n \n pub type LineChanges = HashMap;\n \n-pub fn get_git_diff(filename: &Path) -> Option {\n- let repo = Repository::discover(filename).ok()?;\n-\n- let repo_path_absolute = fs::canonicalize(repo.workdir()?).ok()?;\n-\n- let filepath_absolute = fs::canonicalize(filename).ok()?;\n- let filepath_relative_to_repo = filepath_absolute.strip_prefix(&repo_path_absolute).ok()?;\n-\n- let mut diff_options = DiffOptions::new();\n- let pathspec = filepath_relative_to_repo.into_c_string().ok()?;\n- diff_options.pathspec(pathspec);\n- diff_options.context_lines(0);\n-\n- let diff = repo\n- .diff_index_to_workdir(None, Some(&mut diff_options))\n- .ok()?;\n-\n- let mut line_changes: LineChanges = HashMap::new();\n-\n- let mark_section =\n- |line_changes: &mut LineChanges, start: u32, end: i32, change: LineChange| {\n- for line in start..=end as u32 {\n- line_changes.insert(line, change);\n- }\n- };\n-\n- let _ = diff.foreach(\n- &mut |_, _| true,\n- None,\n- Some(&mut |delta, hunk| {\n- let path = delta.new_file().path().unwrap_or_else(|| Path::new(\"\"));\n-\n- if filepath_relative_to_repo != path {\n- return false;\n+fn collect_changes_from_hunks(hunks: HunkIter) -> Option {\n+ let mut changes: LineChanges = HashMap::new();\n+ for hunk in hunks {\n+ if hunk.before.is_empty() && !hunk.after.is_empty() {\n+ for line in hunk.after {\n+ changes.insert(line + 1, LineChange::Added);\n }\n-\n- let old_lines = hunk.old_lines();\n- let new_start = hunk.new_start();\n- let new_lines = hunk.new_lines();\n- let new_end = (new_start + new_lines) as i32 - 1;\n-\n- if old_lines == 0 && new_lines > 0 {\n- mark_section(&mut line_changes, new_start, new_end, LineChange::Added);\n- } else if new_lines == 0 && old_lines > 0 {\n- if new_start == 0 {\n- mark_section(&mut line_changes, 1, 1, LineChange::RemovedAbove);\n- } else {\n- mark_section(\n- &mut line_changes,\n- new_start,\n- new_start as i32,\n- LineChange::RemovedBelow,\n- );\n- }\n+ } else if hunk.after.is_empty() && !hunk.before.is_empty() {\n+ if hunk.after.start == 0 {\n+ changes.insert(1, LineChange::RemovedAbove);\n } else {\n- mark_section(&mut line_changes, new_start, new_end, LineChange::Modified);\n+ changes.insert(hunk.after.start, LineChange::RemovedBelow);\n+ }\n+ } else {\n+ for line in hunk.after {\n+ changes.insert(line + 1, LineChange::Modified);\n }\n+ }\n+ }\n \n- true\n- }),\n- None,\n+ Some(changes)\n+}\n+\n+pub fn get_git_diff(filename: &Path) -> Option {\n+ let filepath_absolute = filename.canonicalize().ok()?;\n+ let repository = gix::discover(filepath_absolute.parent().ok()?).ok()?;\n+ let repo_path_absolute = repository.workdir()?.canonicalize().ok()?;\n+ let filepath_relative_to_repo = gix::path::to_unix_separators_on_windows(gix::path::into_bstr(\n+ filepath_absolute.strip_prefix(&repo_path_absolute).ok()?,\n+ ));\n+ let index = repository.index_or_load_from_head_or_empty().ok()?;\n+ let index_entry = index.entry_by_path(filepath_relative_to_repo.as_ref())?;\n+ let mut cache = repository\n+ .diff_resource_cache(\n+ Mode::ToGit,\n+ WorktreeRoots {\n+ old_root: None,\n+ new_root: repository.workdir().map(Path::to_path_buf),\n+ },\n+ )\n+ .ok()?;\n+ cache\n+ .set_resource(\n+ index_entry.id,\n+ index_entry.mode.to_tree_entry_mode()?.kind(),\n+ filepath_relative_to_repo.as_ref(),\n+ ResourceKind::OldOrSource,\n+ &repository,\n+ )\n+ .ok()?;\n+ cache\n+ .set_resource(\n+ repository.object_hash().null(),\n+ EntryKind::Blob,\n+ filepath_relative_to_repo.as_ref(),\n+ ResourceKind::NewOrDestination,\n+ &repository,\n+ )\n+ .ok()?;\n+ let diff = gix::diff::blob::diff_with_slider_heuristics(\n+ Algorithm::Histogram,\n+ &cache.prepare_diff().ok()?.interned_input(),\n );\n \n- Some(line_changes)\n+ collect_changes_from_hunks(diff.hunks())\n+}\n+\n+#[cfg(test)]\n+mod tests {\n+ use super::{get_git_diff, LineChange};\n+ use std::path::{Path, PathBuf};\n+ use std::process::Command;\n+\n+ fn git(repo: &Path, args: &[&str]) {\n+ let output = Command::new(\"git\")\n+ .args(args)\n+ .current_dir(repo)\n+ .output()\n+ .expect(\"git command can run\");\n+ assert!(\n+ output.status.success(),\n+ \"git {args:?} failed\\nstdout: {}\\nstderr: {}\",\n+ String::from_utf8_lossy(&output.stdout),\n+ String::from_utf8_lossy(&output.stderr)\n+ );\n+ }\n+\n+ fn setup_repo() -> tempfile::TempDir {\n+ let dir = tempfile::tempdir().expect(\"can create temporary directory\");\n+ let repo = dir.path();\n+ git(repo, &[\"init\"]);\n+ git(repo, &[\"config\", \"user.email\", \"test@test.test\"]);\n+ git(repo, &[\"config\", \"user.name\", \"Test\"]);\n+ dir\n+ }\n+\n+ fn create_and_track_file(repo: &tempfile::TempDir, filename: &str) -> PathBuf {\n+ let filepath = repo.path().join(filename);\n+ std::fs::write(&filepath, \"file\\n\").expect(\"can write file\");\n+ git(repo.path(), &[\"add\", filename]);\n...[truncated]", "anchor_file": "src/diff.rs", "intent": "Replace libgit2 with gitoxide (#2)\n\nThis is a continuation of https://github.com/sharkdp/bat/pull/3235\n\nThis time all tests pass without any changes :D Looks promising!\n\n**Context**: This PR replaces the usage of `libgit2` with a full Rust implementation of `git`. This was tried [before](https://github.com/sharkdp/bat/pull/3235) but a couple of issues were found in the Rust implementation of `git`. These issues seem to be fixed now. Therefore, I am opening this again and would like to see what the maintainers think. \n\nCC: @byron\n\nReplace libgit2 with gitoxide\n\nUse correct PR number\n\nUse histogram instead of myers for diffing\n\nAdd more tests for git diff\n\ncargo fmt\n\nfix immediate dereference of reference\n\nUpdate to gix 0.83\n\nRegenerate Cargo.lock after rebase\n\nAdd test with fauly git repo version\n\nUpdate gix to 0.85"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "b29e1d55c4901770e36460ee094a49fdc514f793", "candidate_corpus": {"base_commit": "b29e1d55c4901770e36460ee094a49fdc514f793", "type": "repo_at_base_commit"}, "gold": {"files": ["src/bin/bat/app.rs"], "given_files": ["src/bin/bat/main.rs"]}, "id": "380ad276dfb5a3bc4d202a06", "metadata": {"changed_files": ["CHANGELOG.md", "src/bin/bat/app.rs", "src/bin/bat/main.rs"], "created_at": "2026-04-25T16:25:39Z", "fix_commit": "7fcab0616a98b07604935e34a21379cc82c78732", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "src/bin/bat/app.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"src/bin/bat/app.rs": ["app", "bat", "bin"]}}, "merged_at": "2026-04-30T15:09:33Z", "pr": 3700, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/sharkdp/bat/pull/3700"}, "query": {"anchor_diff": "@@ -17,7 +17,6 @@ use std::path::Path;\n use std::process;\n \n use bat::output::{OutputHandle, OutputType};\n-use bat::theme::DetectColorScheme;\n use nu_ansi_term::Color::Green;\n use nu_ansi_term::Style;\n \n@@ -39,7 +38,7 @@ use bat::{\n error::*,\n input::Input,\n style::{StyleComponent, StyleComponents},\n- theme::{color_scheme, default_theme, ColorScheme},\n+ theme::{default_theme, theme, ColorScheme, ThemeOptions},\n MappingTarget, PagingMode,\n };\n \n@@ -197,7 +196,7 @@ pub fn list_themes(\n cfg: &Config,\n config_dir: &Path,\n cache_dir: &Path,\n- detect_color_scheme: DetectColorScheme,\n+ theme_options: ThemeOptions,\n ) -> Result<()> {\n let assets = assets_from_cache_or_binary(cfg.use_custom_assets, cache_dir)?;\n let mut config = cfg.clone();\n@@ -206,7 +205,7 @@ pub fn list_themes(\n config.language = Some(\"Rust\");\n config.style_components = StyleComponents(style);\n \n- let default_theme_name = default_theme(color_scheme(detect_color_scheme).unwrap_or_default());\n+ let default_theme_name = theme(theme_options).to_string();\n let mut buf = String::new();\n let mut handle = OutputHandle::FmtWrite(&mut buf);\n \n@@ -428,7 +427,7 @@ fn run() -> Result {\n };\n run_controller(inputs, &plain_config, cache_dir)\n } else if app.matches.get_flag(\"list-themes\") {\n- list_themes(&config, config_dir, cache_dir, DetectColorScheme::default())?;\n+ list_themes(&config, config_dir, cache_dir, app.theme_options())?;\n Ok(true)\n } else if app.matches.get_flag(\"config-file\") {\n println!(\"{}\", config_file().to_string_lossy());", "anchor_file": "src/bin/bat/main.rs", "intent": "Fixed hardcoded terminal probing when `--list-themes` is called\n\n# Fix: `--list-themes` ignores `--theme` and always probes the terminal\n\n## Problem\n\n`bat --list-themes` unconditionally queried the terminal for its background\ncolor via OSC 10/11 escape sequences, regardless of what `--theme` was set to.\nThis caused display corruption in terminals and multiplexers that do not\nsupport OSC 10/11 (e.g. GNU Screen), even when the user had explicitly chosen\na fixed theme such as `--theme=dark` or `--theme=Dracula`.\n\n## Root cause\n\nThis was a regression introduced in commit bc42149a (\"Merge color scheme\noptions into theme / BAT\\_THEME\"). Before that commit, `list_themes` was\ncalled with the user's actual color-scheme preference\n(`app.color_scheme_preference()`). During the refactor that merged\n`--color-scheme` into `--theme`, the call site was silently changed to the\nhardcoded value `ColorSchemePreference::default()` (equivalent to\n`DetectColorScheme::Auto`), which always attempts a terminal probe when stdout\nis a tty — completely ignoring the user's `--theme` setting.\n\n## Fix\n\n`list_themes` now receives the full `ThemeOptions` (the same struct used\neverywhere else in bat) and computes the `(default)` marker via the existing\n`theme()` function. Since `theme()` already handles all `ThemePreference`\nvariants correctly — only probing for `Auto`, never for `Dark`, `Light`, or\n`Fixed` — this restores the pre-regression behaviour and makes the listing\nconsistent with how bat resolves the theme for normal output.\n\nChanges:\n\n- `App::theme_options` visibility raised to `pub(crate)` so `main.rs` can\n call it at the `--list-themes` site.\n- `list_themes` parameter changed from `DetectColorScheme` to `ThemeOptions`.\n- Default-theme resolution changed from\n `default_theme(color_scheme(det\n...[truncated]"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "a995764d230e49e089febd8e5487c1d61e5d3051", "candidate_corpus": {"base_commit": "a995764d230e49e089febd8e5487c1d61e5d3051", "type": "repo_at_base_commit"}, "gold": {"files": ["src/bin/bat/config.rs", "src/bin/bat/main.rs", "tests/integration_tests.rs"], "given_files": ["src/bin/bat/clap_app.rs"]}, "id": "127a8bc4f9095d1d8604fdec", "metadata": {"changed_files": ["CHANGELOG.md", "doc/long-help.txt", "src/bin/bat/clap_app.rs", "src/bin/bat/config.rs", "src/bin/bat/main.rs", "tests/integration_tests.rs"], "created_at": "2026-04-10T14:36:37Z", "fix_commit": "33045c35582cc20f3a0c27dd092884c6eec42373", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 0, "is_test": false, "path": "src/bin/bat/config.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 1, "deletions": 0, "is_test": false, "path": "src/bin/bat/main.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 52, "deletions": 0, "is_test": true, "path": "tests/integration_tests.rs", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"src/bin/bat/config.rs": ["bat", "bin"], "src/bin/bat/main.rs": ["bat", "bin"], "tests/integration_tests.rs": ["integration_tests", "integration"]}}, "merged_at": "2026-04-12T01:59:03Z", "pr": 3687, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/sharkdp/bat/pull/3687"}, "query": {"anchor_diff": "@@ -240,6 +240,7 @@ pub fn build_app(interactive_output: bool) -> Command {\n .arg(\n Arg::new(\"terminal-width\")\n .long(\"terminal-width\")\n+ .overrides_with(\"terminal-width\")\n .value_name(\"width\")\n .hide_short_help(true)\n .allow_hyphen_values(true)\n@@ -255,10 +256,13 @@ pub fn build_app(interactive_output: bool) -> Command {\n })\n .map_err(|e| e.to_string())\n })\n- .help(\n+ .help(\"Explicitly set the width of the terminal instead of determining it automatically.\")\n+ .long_help(\n \"Explicitly set the width of the terminal instead of determining it \\\n automatically. If prefixed with '+' or '-', the value will be treated \\\n- as an offset to the actual terminal width. See also: '--wrap'.\",\n+ as an offset to the actual terminal width. This can also be configured \\\n+ via the BAT_WIDTH environment variable (e.g. export BAT_WIDTH=\\\"100\\\"). \\\n+ See also: '--wrap'.\",\n ),\n )\n .arg(", "anchor_file": "src/bin/bat/clap_app.rs", "intent": "Support BAT_WIDTH for terminal width\n\n## Summary\n- add `BAT_WIDTH` as an environment-backed alias for `--terminal-width`\n- surface `BAT_WIDTH` in `--diagnostic` output and the terminal-width help text\n- add integration coverage for env-driven width selection and normal CLI override precedence\n\n## Testing\n- `cargo test --lib`\n- `cargo test --test integration_tests`\n\nCloses #3679\n\nSupport BAT_WIDTH as an alias for --terminal-width\n\nUpdate changelog entry for #3687"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "a995764d230e49e089febd8e5487c1d61e5d3051", "candidate_corpus": {"base_commit": "a995764d230e49e089febd8e5487c1d61e5d3051", "type": "repo_at_base_commit"}, "gold": {"files": ["src/bin/bat/main.rs", "src/bin/bat/clap_app.rs", "tests/integration_tests.rs"], "given_files": ["src/bin/bat/config.rs"]}, "id": "73d8986644f1a8db781b5e9f", "metadata": {"changed_files": ["CHANGELOG.md", "doc/long-help.txt", "src/bin/bat/clap_app.rs", "src/bin/bat/config.rs", "src/bin/bat/main.rs", "tests/integration_tests.rs"], "created_at": "2026-04-10T14:36:37Z", "fix_commit": "33045c35582cc20f3a0c27dd092884c6eec42373", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 0, "is_test": false, "path": "src/bin/bat/main.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 6, "deletions": 2, "is_test": false, "path": "src/bin/bat/clap_app.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 52, "deletions": 0, "is_test": true, "path": "tests/integration_tests.rs", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"src/bin/bat/clap_app.rs": ["bat", "bin"], "src/bin/bat/main.rs": ["bat", "bin"], "tests/integration_tests.rs": ["integration_tests", "integration"]}}, "merged_at": "2026-04-12T01:59:03Z", "pr": 3687, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/sharkdp/bat/pull/3687"}, "query": {"anchor_diff": "@@ -153,6 +153,7 @@ fn get_args_from_str(content: &str) -> Result, shell_words::ParseE\n pub fn get_args_from_env_vars() -> Vec {\n [\n (\"--tabs\", \"BAT_TABS\"),\n+ (\"--terminal-width\", \"BAT_WIDTH\"),\n (\"--theme\", bat::theme::env::BAT_THEME),\n (\"--theme-dark\", bat::theme::env::BAT_THEME_DARK),\n (\"--theme-light\", bat::theme::env::BAT_THEME_LIGHT),", "anchor_file": "src/bin/bat/config.rs", "intent": "Support BAT_WIDTH for terminal width\n\n## Summary\n- add `BAT_WIDTH` as an environment-backed alias for `--terminal-width`\n- surface `BAT_WIDTH` in `--diagnostic` output and the terminal-width help text\n- add integration coverage for env-driven width selection and normal CLI override precedence\n\n## Testing\n- `cargo test --lib`\n- `cargo test --test integration_tests`\n\nCloses #3679\n\nSupport BAT_WIDTH as an alias for --terminal-width\n\nUpdate changelog entry for #3687"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "d43db994181f91cfa996f2f3df3b557ba87494e4", "candidate_corpus": {"base_commit": "d43db994181f91cfa996f2f3df3b557ba87494e4", "type": "repo_at_base_commit"}, "gold": {"files": ["rich/default_styles.py"], "given_files": ["rich/traceback.py"]}, "id": "9c6e859d9e9cd61e3495738a", "metadata": {"changed_files": ["rich/default_styles.py", "rich/traceback.py"], "created_at": "2025-03-29T16:12:12Z", "fix_commit": "39fa5eeeffe1153ae6b0ba0f9f68fb3ce8852f99", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "rich/default_styles.py", "signals": ["same_component", "path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"rich/default_styles.py": ["rich"]}}, "merged_at": "2025-03-30T07:23:05Z", "pr": 3678, "ripple_relation": ["same_component", "path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol"], "source_pr": "https://github.com/Textualize/rich/pull/3678"}, "query": {"anchor_diff": "@@ -26,7 +26,7 @@ from pygments.token import Token\n from pygments.util import ClassNotFound\n \n from . import pretty\n-from ._loop import loop_last\n+from ._loop import loop_first_last, loop_last\n from .columns import Columns\n from .console import Console, ConsoleOptions, ConsoleRenderable, RenderResult, group\n from .constrain import Constrain\n@@ -34,7 +34,7 @@ from .highlighter import RegexHighlighter, ReprHighlighter\n from .panel import Panel\n from .scope import render_scope\n from .style import Style\n-from .syntax import Syntax\n+from .syntax import Syntax, SyntaxPosition\n from .text import Text\n from .theme import Theme\n \n@@ -44,6 +44,34 @@ LOCALS_MAX_LENGTH = 10\n LOCALS_MAX_STRING = 80\n \n \n+def _iter_syntax_lines(\n+ start: SyntaxPosition, end: SyntaxPosition\n+) -> Iterable[Tuple[int, int, int]]:\n+ \"\"\"Yield start and end positions per line.\n+\n+ Args:\n+ start: Start position.\n+ end: End position.\n+\n+ Returns:\n+ Iterable of (LINE, COLUMN1, COLUMN2).\n+ \"\"\"\n+\n+ line1, column1 = start\n+ line2, column2 = end\n+\n+ if line1 == line2:\n+ yield line1, column1, column2\n+ else:\n+ for first, last, line_no in loop_first_last(range(line1, line2 + 1)):\n+ if first:\n+ yield line_no, column1, -1\n+ elif last:\n+ yield line_no, 0, column2\n+ else:\n+ yield line_no, 0, -1\n+\n+\n def install(\n *,\n console: Optional[Console] = None,\n@@ -658,17 +686,6 @@ class Traceback:\n path_highlighter = PathHighlighter()\n theme = self.theme\n \n- def read_code(filename: str) -> str:\n- \"\"\"Read files, and cache results on filename.\n-\n- Args:\n- filename (str): Filename to read\n-\n- Returns:\n- str: Contents of file\n- \"\"\"\n- return \"\".join(linecache.getlines(filename))\n-\n def render_locals(frame: Frame) -> Iterable[ConsoleRenderable]:\n if frame.locals:\n yield render_scope(\n@@ -730,7 +747,8 @@ class Traceback:\n continue\n if not suppressed:\n try:\n- code = read_code(frame.filename)\n+ code_lines = linecache.getlines(frame.filename)\n+ code = \"\".join(code_lines)\n if not code:\n # code may be an empty string if the file doesn't exist, OR\n # if the traceback filename is generated dynamically\n@@ -759,12 +777,26 @@ class Traceback:\n else:\n if frame.last_instruction is not None:\n start, end = frame.last_instruction\n- syntax.stylize_range(\n- style=\"traceback.error_range\",\n- start=start,\n- end=end,\n- style_before=True,\n- )\n+\n+ # Stylize a line at a time\n+ # So that indentation isn't underlined (which looks bad)\n+ for line1, column1, column2 in _iter_syntax_lines(start, end):\n+ try:\n+ if column1 == 0:\n+ line = code_lines[line1 - 1]\n+ column1 = len(line) - len(line.lstrip())\n+ if column2 == -1:\n+ column2 = len(code_lines[line1 - 1])\n+ except IndexError:\n+ # Being defensive here\n+ # If last_instruction reports a line out-of-bounds, we don't want to crash\n+ continue\n+\n+ syntax.stylize_range(\n+ style=\"traceback.error_range\",\n+ start=(line1, column1),\n+ end=(line1, column2),\n+ )\n yield (\n Columns(\n [", "anchor_file": "rich/traceback.py", "intent": "Don't underline indentation\n\nPrevent code highlights in exceptions from highlighting indentation. Previously indentation was underline, which didn't look good.\n\"Screenshot\n\"Screenshot\n\nDon't underline indentation\n\nsimplify"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "d43db994181f91cfa996f2f3df3b557ba87494e4", "candidate_corpus": {"base_commit": "d43db994181f91cfa996f2f3df3b557ba87494e4", "type": "repo_at_base_commit"}, "gold": {"files": ["rich/traceback.py"], "given_files": ["rich/default_styles.py"]}, "id": "d98482c76744ae478b4cda4a", "metadata": {"changed_files": ["rich/default_styles.py", "rich/traceback.py"], "created_at": "2025-03-29T16:12:12Z", "fix_commit": "39fa5eeeffe1153ae6b0ba0f9f68fb3ce8852f99", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 52, "deletions": 20, "is_test": false, "path": "rich/traceback.py", "signals": ["same_component", "path_token_overlap", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"rich/traceback.py": ["traceback", "rich"]}}, "merged_at": "2025-03-30T07:23:05Z", "pr": 3678, "ripple_relation": ["same_component", "path_token_overlap", "anchor_diff_mentions_gold_module", "shared_changed_symbol"], "source_pr": "https://github.com/Textualize/rich/pull/3678"}, "query": {"anchor_diff": "@@ -120,7 +120,7 @@ DEFAULT_STYLES: Dict[str, Style] = {\n \"traceback.exc_type\": Style(color=\"bright_red\", bold=True),\n \"traceback.exc_value\": Style.null(),\n \"traceback.offset\": Style(color=\"bright_red\", bold=True),\n- \"traceback.error_range\": Style(underline=True, bold=True, dim=False),\n+ \"traceback.error_range\": Style(underline=True, bold=True),\n \"traceback.note\": Style(color=\"green\", bold=True),\n \"bar.back\": Style(color=\"grey23\"),\n \"bar.complete\": Style(color=\"rgb(249,38,114)\"),", "anchor_file": "rich/default_styles.py", "intent": "Don't underline indentation\n\nPrevent code highlights in exceptions from highlighting indentation. Previously indentation was underline, which didn't look good.\n\"Screenshot\n\"Screenshot\n\nDon't underline indentation\n\nsimplify"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "2ffd9d69763ed09269214c8ffe2fe435581febd8", "candidate_corpus": {"base_commit": "2ffd9d69763ed09269214c8ffe2fe435581febd8", "type": "repo_at_base_commit"}, "gold": {"files": ["rich/default_styles.py"], "given_files": ["rich/traceback.py"]}, "id": "711f79ebe1ed760c3d405ee9", "metadata": {"changed_files": ["CHANGELOG.md", "rich/default_styles.py", "rich/traceback.py"], "created_at": "2025-03-29T13:52:40Z", "fix_commit": "a48a5b309f9273ffba85fb9491b974634c8f7ab9", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 1, "deletions": 0, "is_test": false, "path": "rich/default_styles.py", "signals": ["same_component", "path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"rich/default_styles.py": ["rich"]}}, "merged_at": "2025-03-30T11:14:46Z", "pr": 3677, "ripple_relation": ["same_component", "path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol"], "source_pr": "https://github.com/Textualize/rich/pull/3677"}, "query": {"anchor_diff": "@@ -28,7 +28,14 @@ from pygments.util import ClassNotFound\n from . import pretty\n from ._loop import loop_first_last, loop_last\n from .columns import Columns\n-from .console import Console, ConsoleOptions, ConsoleRenderable, RenderResult, group\n+from .console import (\n+ Console,\n+ ConsoleOptions,\n+ ConsoleRenderable,\n+ Group,\n+ RenderResult,\n+ group,\n+)\n from .constrain import Constrain\n from .highlighter import RegexHighlighter, ReprHighlighter\n from .panel import Panel\n@@ -128,26 +135,25 @@ def install(\n value: BaseException,\n traceback: Optional[TracebackType],\n ) -> None:\n- traceback_console.print(\n- Traceback.from_exception(\n- type_,\n- value,\n- traceback,\n- width=width,\n- code_width=code_width,\n- extra_lines=extra_lines,\n- theme=theme,\n- word_wrap=word_wrap,\n- show_locals=show_locals,\n- locals_max_length=locals_max_length,\n- locals_max_string=locals_max_string,\n- locals_hide_dunder=locals_hide_dunder,\n- locals_hide_sunder=bool(locals_hide_sunder),\n- indent_guides=indent_guides,\n- suppress=suppress,\n- max_frames=max_frames,\n- )\n+ exception_traceback = Traceback.from_exception(\n+ type_,\n+ value,\n+ traceback,\n+ width=width,\n+ code_width=code_width,\n+ extra_lines=extra_lines,\n+ theme=theme,\n+ word_wrap=word_wrap,\n+ show_locals=show_locals,\n+ locals_max_length=locals_max_length,\n+ locals_max_string=locals_max_string,\n+ locals_hide_dunder=locals_hide_dunder,\n+ locals_hide_sunder=bool(locals_hide_sunder),\n+ indent_guides=indent_guides,\n+ suppress=suppress,\n+ max_frames=max_frames,\n )\n+ traceback_console.print(exception_traceback)\n \n def ipy_excepthook_closure(ip: Any) -> None: # pragma: no cover\n tb_data = {} # store information about showtraceback call\n@@ -230,6 +236,8 @@ class Stack:\n is_cause: bool = False\n frames: List[Frame] = field(default_factory=list)\n notes: List[str] = field(default_factory=list)\n+ is_group: bool = False\n+ exceptions: List[\"Trace\"] = field(default_factory=list)\n \n \n @dataclass\n@@ -450,6 +458,22 @@ class Traceback:\n notes=notes,\n )\n \n+ if sys.version_info >= (3, 11):\n+ if isinstance(exc_value, (BaseExceptionGroup, ExceptionGroup)):\n+ stack.is_group = True\n+ for exception in exc_value.exceptions:\n+ stack.exceptions.append(\n+ Traceback.extract(\n+ type(exception),\n+ exception,\n+ exception.__traceback__,\n+ show_locals=show_locals,\n+ locals_max_length=locals_max_length,\n+ locals_hide_dunder=locals_hide_dunder,\n+ locals_hide_sunder=locals_hide_sunder,\n+ )\n+ )\n+\n if isinstance(exc_value, SyntaxError):\n stack.syntax_error = _SyntaxError(\n offset=exc_value.offset or 0,\n@@ -558,6 +582,7 @@ class Traceback:\n break # pragma: no cover\n \n trace = Trace(stacks=stacks)\n+\n return trace\n \n def __rich_console__(\n@@ -590,7 +615,9 @@ class Traceback:\n )\n \n highlighter = ReprHighlighter()\n- for last, stack in loop_last(reversed(self.trace.stacks)):\n+\n+ @group()\n+ def render_stack(stack: Stack, last: bool) -> RenderResult:\n if stack.frames:\n stack_renderable: ConsoleRenderable = Panel(\n self._render_stack(stack),\n@@ -632,6 +659,21 @@ class Traceback:\n for note in stack.notes:\n yield Text.assemble((\"[NOTE] \", \"traceback.note\"), highlighter(note))\n \n+ if stack.is_group:\n+ for group_no, group_exception in enumerate(stack.exceptions, 1):\n+ grouped_exceptions: List[Group] = []\n+ for group_last, group_stack in loop_last(group_exception.stacks):\n+ grouped_exceptions.append(render_stack(group_stack, group_last))\n+ yield \"\"\n+ yield Constrain(\n+ Panel(\n+ Group(*grouped_exceptions),\n+ title=f\"Sub-exception #{group_no}\",\n+ border_style=\"traceback.group.border\",\n+ ),\n+ self.width,\n+ )\n+\n if not last:\n if stack.is_cause:\n yield Text.from_markup(\n@@ -642,6 +684,9 @@ class Traceback:\n \"\\n[i]During handling of the above exception, another exception occurred:\\n\",\n )\n \n+ for last, stack in loop_last(reversed(self.trace.stacks)):\n+ yield render_stack(stack, last)\n+\n @group()\n def _render_syntax_error(self, syntax_error: _SyntaxError) -> RenderResult:\n highlighter = ReprHighlighter()", "anchor_file": "rich/traceback.py", "intent": "exception groups\n\nAdds support for exception groups\n\nimplement exception groups\n\ngroup exceptions\n\nfor MyPy\n\ntyping fix\n\nremove debug\n\nstyle tweak\n\nMerge branch 'master' into exception-groups\n\nchangelog"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "2ffd9d69763ed09269214c8ffe2fe435581febd8", "candidate_corpus": {"base_commit": "2ffd9d69763ed09269214c8ffe2fe435581febd8", "type": "repo_at_base_commit"}, "gold": {"files": ["rich/traceback.py"], "given_files": ["rich/default_styles.py"]}, "id": "9a4ef57b168808eeb8bd2390", "metadata": {"changed_files": ["CHANGELOG.md", "rich/default_styles.py", "rich/traceback.py"], "created_at": "2025-03-29T13:52:40Z", "fix_commit": "a48a5b309f9273ffba85fb9491b974634c8f7ab9", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 66, "deletions": 21, "is_test": false, "path": "rich/traceback.py", "signals": ["same_component", "path_token_overlap", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"rich/traceback.py": ["traceback", "rich"]}}, "merged_at": "2025-03-30T11:14:46Z", "pr": 3677, "ripple_relation": ["same_component", "path_token_overlap", "anchor_diff_mentions_gold_module", "shared_changed_symbol"], "source_pr": "https://github.com/Textualize/rich/pull/3677"}, "query": {"anchor_diff": "@@ -122,6 +122,7 @@ DEFAULT_STYLES: Dict[str, Style] = {\n \"traceback.offset\": Style(color=\"bright_red\", bold=True),\n \"traceback.error_range\": Style(underline=True, bold=True),\n \"traceback.note\": Style(color=\"green\", bold=True),\n+ \"traceback.group.border\": Style(color=\"magenta\"),\n \"bar.back\": Style(color=\"grey23\"),\n \"bar.complete\": Style(color=\"rgb(249,38,114)\"),\n \"bar.finished\": Style(color=\"rgb(114,156,31)\"),", "anchor_file": "rich/default_styles.py", "intent": "exception groups\n\nAdds support for exception groups\n\nimplement exception groups\n\ngroup exceptions\n\nfor MyPy\n\ntyping fix\n\nremove debug\n\nstyle tweak\n\nMerge branch 'master' into exception-groups\n\nchangelog"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "2b5d648b2c62960deb6439f4204ed8fa6eb3cf7b", "candidate_corpus": {"base_commit": "2b5d648b2c62960deb6439f4204ed8fa6eb3cf7b", "type": "repo_at_base_commit"}, "gold": {"files": ["rich/traceback.py", "tests/test_traceback.py"], "given_files": ["rich/default_styles.py"]}, "id": "524d2c466f5ef9177eeeacae", "metadata": {"changed_files": ["CHANGELOG.md", "rich/default_styles.py", "rich/traceback.py", "tests/test_traceback.py"], "created_at": "2025-03-28T13:50:53Z", "fix_commit": "edc6b0a39b6df1c0e26d409bb5c5eda7149b2de6", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 11, "deletions": 1, "is_test": false, "path": "rich/traceback.py", "signals": ["same_component", "path_token_overlap", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}, {"additions": 15, "deletions": 0, "is_test": true, "path": "tests/test_traceback.py", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"rich/traceback.py": ["traceback", "rich"], "tests/test_traceback.py": ["traceback"]}}, "merged_at": "2025-03-28T14:37:24Z", "pr": 3676, "ripple_relation": ["same_component", "path_token_overlap", "anchor_diff_mentions_gold_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/Textualize/rich/pull/3676"}, "query": {"anchor_diff": "@@ -121,6 +121,7 @@ DEFAULT_STYLES: Dict[str, Style] = {\n \"traceback.exc_value\": Style.null(),\n \"traceback.offset\": Style(color=\"bright_red\", bold=True),\n \"traceback.error_range\": Style(underline=True, bold=True, dim=False),\n+ \"traceback.note\": Style(color=\"green\", bold=True),\n \"bar.back\": Style(color=\"grey23\"),\n \"bar.complete\": Style(color=\"rgb(249,38,114)\"),\n \"bar.finished\": Style(color=\"rgb(114,156,31)\"),", "anchor_file": "rich/default_styles.py", "intent": "Notes\n\nAdd support for Exception.__notes__\n\nrender notes in traceback\n\nchangelog\n\nadded trest\n\nsimplify\n\nfix typing\n\nnotes added in 3.11"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "2b5d648b2c62960deb6439f4204ed8fa6eb3cf7b", "candidate_corpus": {"base_commit": "2b5d648b2c62960deb6439f4204ed8fa6eb3cf7b", "type": "repo_at_base_commit"}, "gold": {"files": ["rich/default_styles.py", "tests/test_traceback.py"], "given_files": ["rich/traceback.py"]}, "id": "b89ab11c4a58a6c96150c1d0", "metadata": {"changed_files": ["CHANGELOG.md", "rich/default_styles.py", "rich/traceback.py", "tests/test_traceback.py"], "created_at": "2025-03-28T13:50:53Z", "fix_commit": "edc6b0a39b6df1c0e26d409bb5c5eda7149b2de6", "generated_at": "2026-10-17T09:00:50+00:00", "gold_evidence": [{"additions": 1, "deletions": 0, "is_test": false, "path": "rich/default_styles.py", "signals": ["same_component", "path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 15, "deletions": 0, "is_test": true, "path": "tests/test_traceback.py", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"rich/default_styles.py": ["rich"], "tests/test_traceback.py": ["traceback"]}}, "merged_at": "2025-03-28T14:37:24Z", "pr": 3676, "ripple_relation": ["same_component", "path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/Textualize/rich/pull/3676"}, "query": {"anchor_diff": "@@ -191,6 +191,7 @@ class _SyntaxError:\n line: str\n lineno: int\n msg: str\n+ notes: List[str] = field(default_factory=list)\n \n \n @dataclass\n@@ -200,6 +201,7 @@ class Stack:\n syntax_error: Optional[_SyntaxError] = None\n is_cause: bool = False\n frames: List[Frame] = field(default_factory=list)\n+ notes: List[str] = field(default_factory=list)\n \n \n @dataclass\n@@ -403,6 +405,8 @@ class Traceback:\n \n from rich import _IMPORT_CWD\n \n+ notes: List[str] = getattr(exc_value, \"__notes__\", None) or []\n+\n def safe_str(_object: Any) -> str:\n \"\"\"Don't allow exceptions from __str__ to propagate.\"\"\"\n try:\n@@ -415,6 +419,7 @@ class Traceback:\n exc_type=safe_str(exc_type.__name__),\n exc_value=safe_str(exc_value),\n is_cause=is_cause,\n+ notes=notes,\n )\n \n if isinstance(exc_value, SyntaxError):\n@@ -424,13 +429,14 @@ class Traceback:\n lineno=exc_value.lineno or 0,\n line=exc_value.text or \"\",\n msg=exc_value.msg,\n+ notes=notes,\n )\n \n stacks.append(stack)\n append = stack.frames.append\n \n def get_locals(\n- iter_locals: Iterable[Tuple[str, object]]\n+ iter_locals: Iterable[Tuple[str, object]],\n ) -> Iterable[Tuple[str, object]]:\n \"\"\"Extract locals from an iterator of key pairs.\"\"\"\n if not (locals_hide_dunder or locals_hide_sunder):\n@@ -569,6 +575,7 @@ class Traceback:\n stack_renderable = Constrain(stack_renderable, self.width)\n with console.use_theme(traceback_theme):\n yield stack_renderable\n+\n if stack.syntax_error is not None:\n with console.use_theme(traceback_theme):\n yield Constrain(\n@@ -594,6 +601,9 @@ class Traceback:\n else:\n yield Text.assemble((f\"{stack.exc_type}\", \"traceback.exc_type\"))\n \n+ for note in stack.notes:\n+ yield Text.assemble((\"[NOTE] \", \"traceback.note\"), highlighter(note))\n+\n if not last:\n if stack.is_cause:\n yield Text.from_markup(", "anchor_file": "rich/traceback.py", "intent": "Notes\n\nAdd support for Exception.__notes__\n\nrender notes in traceback\n\nchangelog\n\nadded trest\n\nsimplify\n\nfix typing\n\nnotes added in 3.11"}, "repo": "Textualize/rich", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "a1e7c0ab4ae87d388e2f2922a25f15b4ca5f62de", "candidate_corpus": {"base_commit": "a1e7c0ab4ae87d388e2f2922a25f15b4ca5f62de", "type": "repo_at_base_commit"}, "gold": {"files": ["src/syntax_mapping/builtin.rs"], "given_files": ["src/syntax_mapping.rs"]}, "id": "a2f1b2243d3a2b579d6b5330", "metadata": {"changed_files": ["CHANGELOG.md", "build/syntax_mapping.rs", "src/syntax_mapping.rs", "src/syntax_mapping/builtin.rs", "src/syntax_mapping/builtins/README.md", "src/syntax_mapping/builtins/common/50-bazel.toml"], "created_at": "2026-02-01T12:36:26Z", "fix_commit": "780fdeb88845644b7e8b890416e7c6fa0a4292dc", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 5, "deletions": 5, "is_test": false, "path": "src/syntax_mapping/builtin.rs", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"src/syntax_mapping/builtin.rs": ["builtin", "mapping", "syntax"]}}, "merged_at": "2026-03-22T18:14:06Z", "pr": 3576, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol"], "source_pr": "https://github.com/sharkdp/bat/pull/3576"}, "query": {"anchor_diff": "@@ -17,9 +17,16 @@ use ignored_suffixes::IgnoredSuffixes;\n mod builtin;\n pub mod ignored_suffixes;\n \n-fn make_glob_matcher(from: &str) -> Result {\n+/// Whether a glob pattern should be matched case-sensitively or case-insensitively.\n+#[derive(Debug, Clone, Copy, PartialEq, Eq)]\n+pub(crate) enum Case {\n+ Sensitive,\n+ Insensitive,\n+}\n+\n+fn make_glob_matcher(from: &str, case: Case) -> Result {\n let matcher = GlobBuilder::new(from)\n- .case_insensitive(true)\n+ .case_insensitive(matches!(case, Case::Insensitive))\n .literal_separator(true)\n .build()?\n .compile_matcher();\n@@ -97,7 +104,14 @@ impl<'a> SyntaxMapping<'a> {\n }\n \n pub fn insert(&mut self, from: &str, to: MappingTarget<'a>) -> Result<()> {\n- let matcher = make_glob_matcher(from)?;\n+ let matcher = make_glob_matcher(from, Case::Insensitive)?;\n+ self.custom_mappings.push((matcher, to));\n+ Ok(())\n+ }\n+\n+ /// Like [`Self::insert`], but the glob pattern is matched case-sensitively.\n+ pub fn insert_case_sensitive(&mut self, from: &str, to: MappingTarget<'a>) -> Result<()> {\n+ let matcher = make_glob_matcher(from, Case::Sensitive)?;\n self.custom_mappings.push((matcher, to));\n Ok(())\n }\n@@ -261,4 +275,41 @@ mod tests {\n Some(MappingTarget::MapTo(\"alpha\"))\n );\n }\n+\n+ #[test]\n+ fn case_sensitive_custom_mappings_work() {\n+ let mut map = SyntaxMapping::new();\n+ map.insert_case_sensitive(\"MY_SPECIAL_FILE\", MappingTarget::MapTo(\"Python\"))\n+ .ok();\n+\n+ // Exact case matches\n+ assert_eq!(\n+ map.get_syntax_for(\"/path/to/MY_SPECIAL_FILE\"),\n+ Some(MappingTarget::MapTo(\"Python\"))\n+ );\n+ // Different case should NOT match the case-sensitive rule\n+ assert_eq!(map.get_syntax_for(\"/path/to/my_special_file\"), None);\n+ assert_eq!(map.get_syntax_for(\"/path/to/My_Special_File\"), None);\n+ }\n+\n+ #[test]\n+ fn builtin_mappings_build_is_case_sensitive() {\n+ let map = SyntaxMapping::new();\n+\n+ // \"BUILD\" (uppercase) should map to Python via case-sensitive builtin\n+ assert_eq!(\n+ map.get_syntax_for(\"/path/to/BUILD\"),\n+ Some(MappingTarget::MapTo(\"Python\"))\n+ );\n+ // \"build\" (lowercase) should still map to MapToUnknown\n+ assert_eq!(\n+ map.get_syntax_for(\"/path/to/build\"),\n+ Some(MappingTarget::MapToUnknown)\n+ );\n+ // Mixed case should NOT match the Python rule\n+ assert_eq!(\n+ map.get_syntax_for(\"/path/to/Build\"),\n+ Some(MappingTarget::MapToUnknown)\n+ );\n+ }\n }", "anchor_file": "src/syntax_mapping.rs", "intent": "feat: Map BUILD to Python (Starlark) for Bazel (fixes #3575)\n\n@keith-hall like this, for #3575 ?\n\nFull disclosure: I have NOT actually tested this... as in, for #3575 I HAVE tested `bat --map-syntax='BUILD:Python' BUILD` locally on a pre-built binary, and looking around https://github.com/sharkdp/bat/tree/master/src/syntax_mapping/builtins/common I kinda gathered that's what you meant with your comment in #3575 - but I haven't actually rebuilt `bat` with this... but it looks about right (I hope).\n\nfeat: Map BUILD to Python (Starlark) for Bazel (fixes #3575)\n\ndocs: Document mapping BUILD to Python (Starlark) for Bazel in CHANGELOG.md (see #3576)\n\nAdd case-sensitive glob support to syntax mapping\n\nMerge remote-tracking branch 'origin/master' into patch-2\n\nRefactor: string-or-struct matcher syntax, Case enum, remove case_sensitive_mappings table\n\nMerge branch 'master' into patch-2\n\ncargo fmt\n\nimprovements from PR review"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "eb2a8e29c7681d1e371ff8eda4512e7c101c2a2d", "candidate_corpus": {"base_commit": "eb2a8e29c7681d1e371ff8eda4512e7c101c2a2d", "type": "repo_at_base_commit"}, "gold": {"files": ["src/preprocessor.rs", "tests/integration_tests.rs"], "given_files": ["src/printer.rs"]}, "id": "03737feb38a4d7c6a3ff3dff", "metadata": {"changed_files": ["CHANGELOG.md", "README.md", "src/preprocessor.rs", "src/printer.rs", "tests/examples/git-commit.man", "tests/examples/overstrike.txt", "tests/integration_tests.rs"], "created_at": "2025-12-05T13:29:37Z", "fix_commit": "9bf344f760e7644c2ecf6b6d2c9748b1c425611a", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 50, "deletions": 0, "is_test": false, "path": "src/preprocessor.rs", "signals": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}, {"additions": 67, "deletions": 0, "is_test": true, "path": "tests/integration_tests.rs", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_stem_hint"], "nonfatal_hits": {"src/preprocessor.rs": ["preprocessor"]}}, "merged_at": "2025-12-11T06:36:18Z", "pr": 3517, "ripple_relation": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/sharkdp/bat/pull/3517"}, "query": {"anchor_diff": "@@ -29,8 +29,7 @@ use crate::error::*;\n use crate::input::OpenedInput;\n use crate::line_range::{MaxBufferedLineNumber, RangeCheckResult};\n use crate::output::OutputHandle;\n-use crate::preprocessor::strip_ansi;\n-use crate::preprocessor::{expand_tabs, replace_nonprintable};\n+use crate::preprocessor::{expand_tabs, replace_nonprintable, strip_ansi, strip_overstrike};\n use crate::style::StyleComponent;\n use crate::terminal::{as_terminal_escaped, to_ansi_color};\n use crate::vscreen::{AnsiStyle, EscapeSequence, EscapeSequenceIterator};\n@@ -199,6 +198,7 @@ pub(crate) struct InteractivePrinter<'a> {\n background_color_highlight: Option,\n consecutive_empty_lines: usize,\n strip_ansi: bool,\n+ strip_overstrike: bool,\n }\n \n impl<'a> InteractivePrinter<'a> {\n@@ -263,17 +263,22 @@ impl<'a> InteractivePrinter<'a> {\n || matches!(config.binary, BinaryBehavior::AsText))\n && (config.colored_output || config.strip_ansi == StripAnsiMode::Auto);\n \n- let (is_plain_text, highlighter_from_set) = if needs_to_match_syntax {\n+ let (is_plain_text, strip_overstrike, highlighter_from_set) = if needs_to_match_syntax {\n // Determine the type of syntax for highlighting\n const PLAIN_TEXT_SYNTAX: &str = \"Plain Text\";\n+ const MANPAGE_SYNTAX: &str = \"Manpage\";\n+ const COMMAND_HELP_SYNTAX: &str = \"Command Help\";\n match assets.get_syntax(config.language, input, &config.syntax_mapping) {\n Ok(syntax_in_set) => (\n syntax_in_set.syntax.name == PLAIN_TEXT_SYNTAX,\n+ syntax_in_set.syntax.name == MANPAGE_SYNTAX\n+ || syntax_in_set.syntax.name == COMMAND_HELP_SYNTAX,\n Some(HighlighterFromSet::new(syntax_in_set, theme)),\n ),\n \n Err(Error::UndetectedSyntax(_)) => (\n true,\n+ false,\n Some(\n assets\n .find_syntax_by_name(PLAIN_TEXT_SYNTAX)?\n@@ -285,7 +290,7 @@ impl<'a> InteractivePrinter<'a> {\n Err(e) => return Err(e),\n }\n } else {\n- (false, None)\n+ (false, false, None)\n };\n \n // Determine when to strip ANSI sequences\n@@ -310,6 +315,7 @@ impl<'a> InteractivePrinter<'a> {\n background_color_highlight,\n consecutive_empty_lines: 0,\n strip_ansi,\n+ strip_overstrike,\n })\n }\n \n@@ -622,6 +628,12 @@ impl Printer for InteractivePrinter<'_> {\n }\n };\n \n+ if self.strip_overstrike {\n+ if let Some(pos) = line.find('\\x08') {\n+ line = strip_overstrike(&line, pos).into();\n+ }\n+ }\n+\n // If ANSI escape sequences are supposed to be stripped, do it before syntax highlighting.\n if self.strip_ansi {\n line = strip_ansi(&line).into()", "anchor_file": "src/printer.rs", "intent": "Improve native man pages and command help syntax highlighting by stripping overstriking\n\nPotentially fixes #652, #2479, #2568, #3025, #3053\n\nI noticed that running `git commit --help | bat -plhelp` displayed text with visible `^H` characters and doubled letters. I realized that this happens because man pages use something called overstriking where (similar to a typewriter) a character is typed twice over each other. `bat` was styling the page and passing through the `^H` which lead to this mixed output.\n\n\"Screenshot\n\nSo as a solution I introduced a `strip_overstrike()` function to simply remove the backspace formatting to allow syntax highlighters to modify the output undisturbed and applies this stripping in both `SimplePrinter` and `InteractivePrinter`. `Cow` is used to avoid allocation when no backspaces are present. \n\nI am not an overly heavy user of `bat` but in my testing of this fix, I tried to verify that:\n- Now `MANPAGER=\"bat -p -l man\" man ls` displays cleanly.\n- `git commit --help | bat -plhelp` now works correctly.\n- `--binary=as-text` still preserves raw bytes.\n\nI am not sure if there are other scenarios that I missed where stripping the overstriking might be unintentional.\n\nAfter all, the above renders like this with this patch:\n\n\"Screenshot\n\nOn as side note: I realized that `git commit --help | bat -plhelp` displays the text not full-width but this is coming from `git commit --help` when it detects that its output is being piped. One workaround is to run `MANWI\n...[truncated]"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "eb2a8e29c7681d1e371ff8eda4512e7c101c2a2d", "candidate_corpus": {"base_commit": "eb2a8e29c7681d1e371ff8eda4512e7c101c2a2d", "type": "repo_at_base_commit"}, "gold": {"files": ["src/printer.rs", "tests/integration_tests.rs"], "given_files": ["src/preprocessor.rs"]}, "id": "7487210838994b6ebdc3a93b", "metadata": {"changed_files": ["CHANGELOG.md", "README.md", "src/preprocessor.rs", "src/printer.rs", "tests/examples/git-commit.man", "tests/examples/overstrike.txt", "tests/integration_tests.rs"], "created_at": "2025-12-05T13:29:37Z", "fix_commit": "9bf344f760e7644c2ecf6b6d2c9748b1c425611a", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 16, "deletions": 4, "is_test": false, "path": "src/printer.rs", "signals": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 67, "deletions": 0, "is_test": true, "path": "tests/integration_tests.rs", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": [], "nonfatal_hits": {}}, "merged_at": "2025-12-11T06:36:18Z", "pr": 3517, "ripple_relation": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/sharkdp/bat/pull/3517"}, "query": {"anchor_diff": "@@ -149,6 +149,35 @@ pub fn strip_ansi(line: &str) -> String {\n buffer\n }\n \n+/// Strips overstrike sequences (backspace formatting) from input.\n+///\n+/// Overstrike formatting is used by man pages and some help output:\n+/// - Bold: `X\\x08X` (character, backspace, same character)\n+/// - Underline: `_\\x08X` (underscore, backspace, character)\n+///\n+/// This function removes these sequences, keeping only the visible character.\n+/// `first_backspace` is the position of the first backspace in the line.\n+pub fn strip_overstrike(line: &str, first_backspace: usize) -> String {\n+ let mut output = String::with_capacity(line.len());\n+ output.push_str(&line[..first_backspace]);\n+ output.pop();\n+\n+ let mut remaining = &line[first_backspace + 1..];\n+\n+ loop {\n+ if let Some(pos) = remaining.find('\\x08') {\n+ output.push_str(&remaining[..pos]);\n+ output.pop();\n+ remaining = &remaining[pos + 1..];\n+ } else {\n+ output.push_str(remaining);\n+ break;\n+ }\n+ }\n+\n+ output\n+}\n+\n #[derive(Debug, PartialEq, Clone, Copy, Default)]\n pub enum StripAnsiMode {\n #[default]\n@@ -211,3 +240,24 @@ fn test_strip_ansi() {\n \"multiple sequences\"\n );\n }\n+\n+#[test]\n+fn test_strip_overstrike() {\n+ // Bold: X\\x08X (same char repeated)\n+ assert_eq!(strip_overstrike(\"H\\x08Hello\", 1), \"Hello\");\n+\n+ // Underline: _\\x08X (underscore before char)\n+ assert_eq!(strip_overstrike(\"_\\x08Hello\", 1), \"Hello\");\n+\n+ // Multiple overstrike sequences\n+ assert_eq!(strip_overstrike(\"B\\x08Bo\\x08ol\\x08ld\\x08d\", 1), \"Bold\");\n+\n+ // Backspace at start of line (nothing to pop)\n+ assert_eq!(strip_overstrike(\"\\x08Hello\", 0), \"Hello\");\n+\n+ // Multiple consecutive backspaces\n+ assert_eq!(strip_overstrike(\"ABC\\x08\\x08\\x08XYZ\", 3), \"XYZ\");\n+\n+ // Unicode with overstrike\n+ assert_eq!(strip_overstrike(\"ä\\x08äöü\", 2), \"äöü\");\n+}", "anchor_file": "src/preprocessor.rs", "intent": "Improve native man pages and command help syntax highlighting by stripping overstriking\n\nPotentially fixes #652, #2479, #2568, #3025, #3053\n\nI noticed that running `git commit --help | bat -plhelp` displayed text with visible `^H` characters and doubled letters. I realized that this happens because man pages use something called overstriking where (similar to a typewriter) a character is typed twice over each other. `bat` was styling the page and passing through the `^H` which lead to this mixed output.\n\n\"Screenshot\n\nSo as a solution I introduced a `strip_overstrike()` function to simply remove the backspace formatting to allow syntax highlighters to modify the output undisturbed and applies this stripping in both `SimplePrinter` and `InteractivePrinter`. `Cow` is used to avoid allocation when no backspaces are present. \n\nI am not an overly heavy user of `bat` but in my testing of this fix, I tried to verify that:\n- Now `MANPAGER=\"bat -p -l man\" man ls` displays cleanly.\n- `git commit --help | bat -plhelp` now works correctly.\n- `--binary=as-text` still preserves raw bytes.\n\nI am not sure if there are other scenarios that I missed where stripping the overstriking might be unintentional.\n\nAfter all, the above renders like this with this patch:\n\n\"Screenshot\n\nOn as side note: I realized that `git commit --help | bat -plhelp` displays the text not full-width but this is coming from `git commit --help` when it detects that its output is being piped. One workaround is to run `MANWI\n...[truncated]"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "1e4a4b765f4a1cad74f3a4204112268f3b303f2f", "candidate_corpus": {"base_commit": "1e4a4b765f4a1cad74f3a4204112268f3b303f2f", "type": "repo_at_base_commit"}, "gold": {"files": ["src/bin/bat/clap_app.rs", "tests/integration_tests.rs"], "given_files": ["src/bin/bat/app.rs"]}, "id": "b7b77a283bb5f87a12ee8b4f", "metadata": {"changed_files": ["CHANGELOG.md", "src/bin/bat/app.rs", "src/bin/bat/clap_app.rs", "tests/integration_tests.rs"], "created_at": "2025-11-05T10:35:12Z", "fix_commit": "70ec3fc24e46cae8f0054a03f92ecfd53c7b98d6", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 17, "deletions": 0, "is_test": false, "path": "src/bin/bat/clap_app.rs", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 38, "deletions": 0, "is_test": true, "path": "tests/integration_tests.rs", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"src/bin/bat/clap_app.rs": ["clap_app", "bat", "bin"]}}, "merged_at": "2025-11-23T20:10:56Z", "pr": 3478, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/sharkdp/bat/pull/3478"}, "query": {"anchor_diff": "@@ -38,6 +38,11 @@ pub fn env_no_color() -> bool {\n env::var_os(\"NO_COLOR\").is_some_and(|x| !x.is_empty())\n }\n \n+enum HelpType {\n+ Short,\n+ Long,\n+}\n+\n pub struct App {\n pub matches: ArgMatches,\n interactive_output: bool,\n@@ -49,38 +54,126 @@ impl App {\n let _ = nu_ansi_term::enable_ansi_support();\n \n let interactive_output = std::io::stdout().is_terminal();\n+ let matches = Self::matches(interactive_output)?;\n+\n+ if matches.get_flag(\"help\") {\n+ let help_type = if wild::args_os().any(|arg| arg == \"--help\") {\n+ HelpType::Long\n+ } else {\n+ HelpType::Short\n+ };\n+\n+ let use_pager = match matches.get_one::(\"paging\").map(|s| s.as_str()) {\n+ Some(\"never\") => false,\n+ _ => !matches.get_flag(\"no-paging\"),\n+ };\n+\n+ let use_color = match matches.get_one::(\"color\").map(|s| s.as_str()) {\n+ Some(\"always\") => true,\n+ Some(\"never\") => false,\n+ _ => interactive_output, // auto: use color if interactive\n+ };\n+\n+ let custom_pager = matches.get_one::(\"pager\").map(|s| s.to_string());\n+ let theme_options = Self::theme_options_from_matches(&matches);\n+\n+ Self::display_help(\n+ interactive_output,\n+ help_type,\n+ use_pager,\n+ use_color,\n+ custom_pager,\n+ theme_options,\n+ )?;\n+ std::process::exit(0);\n+ }\n \n Ok(App {\n- matches: Self::matches(interactive_output)?,\n+ matches,\n interactive_output,\n })\n }\n \n+ fn display_help(\n+ interactive_output: bool,\n+ help_type: HelpType,\n+ use_pager: bool,\n+ use_color: bool,\n+ custom_pager: Option,\n+ theme_options: ThemeOptions,\n+ ) -> Result<()> {\n+ use crate::assets::assets_from_cache_or_binary;\n+ use crate::directories::PROJECT_DIRS;\n+ use bat::{\n+ config::Config,\n+ controller::Controller,\n+ input::Input,\n+ style::{StyleComponent, StyleComponents},\n+ theme::theme,\n+ PagingMode,\n+ };\n+\n+ let mut cmd = clap_app::build_app(interactive_output);\n+ let help_text = match help_type {\n+ HelpType::Short => cmd.render_help().to_string(),\n+ HelpType::Long => cmd.render_long_help().to_string(),\n+ };\n+\n+ let inputs: Vec = vec![Input::from_reader(Box::new(help_text.as_bytes()))];\n+\n+ let paging_mode = if use_pager {\n+ PagingMode::QuitIfOneScreen\n+ } else {\n+ PagingMode::Never\n+ };\n+\n+ let pager = bat::config::get_pager_executable(custom_pager.as_deref());\n+\n+ let help_config = Config {\n+ style_components: StyleComponents::new(StyleComponent::Plain.components(false)),\n+ paging_mode,\n+ pager: pager.as_deref(),\n+ colored_output: use_color,\n+ true_color: use_color,\n+ language: if use_color { Some(\"help\") } else { None },\n+ theme: theme(theme_options).to_string(),\n+ ..Default::default()\n+ };\n+\n+ let cache_dir = PROJECT_DIRS.cache_dir();\n+ let assets = assets_from_cache_or_binary(false, cache_dir)?;\n+ Controller::new(&help_config, &assets)\n+ .run(inputs, None)\n+ .ok();\n+\n+ Ok(())\n+ }\n+\n fn matches(interactive_output: bool) -> Result {\n // Check if we should skip config file processing for special arguments\n- // that don't require full application setup (help, version, diagnostic)\n+ // that don't require full application setup (version, diagnostic)\n let should_skip_config = wild::args_os().any(|arg| {\n matches!(\n arg.to_str(),\n- Some(\"-h\" | \"--help\" | \"-V\" | \"--version\" | \"--diagnostic\" | \"--diagnostics\")\n+ Some(\"-V\" | \"--version\" | \"--diagnostic\" | \"--diagnostics\")\n )\n });\n \n+ // Check if help was requested - help should go through the same code path\n+ // but be forgiving of config file errors\n+ let help_requested =\n+ wild::args_os().any(|arg| matches!(arg.to_str(), Some(\"-h\" | \"--help\")));\n+\n let args = if wild::args_os().nth(1) == Some(\"cache\".into()) {\n // Skip the config file and env vars\n \n wild::args_os().collect::>()\n } else if wild::args_os().any(|arg| arg == \"--no-config\") || should_skip_config {\n // Skip the arguments in bats config file when --no-config is present\n- // or when user requests help, version, or diagnostic information\n+ // or when user requests version or diagnostic information\n \n let mut cli_args = wild::args_os();\n- let mut args = if should_skip_config {\n- // For special commands, don't even try to load env vars that might fail\n- vec![]\n- } else {\n- get_args_from_env_vars()\n- };\n+ let mut args = get_args_from_env_vars();\n \n // Put the zero-th CLI argument (program name) first\n args.insert(0, cli_args.next().unwrap());\n@@ -88,14 +181,28 @@ impl App {\n // .. and the rest at the end\n cli_args.for_each(|a| args.push(a));\n \n+ args\n+ } else if help_requested {\n+ // Help goes through the normal config path but only uses env vars for themes\n+ // to avoid failing on invalid config options\n+ let mut cli_args = wild::args_os();\n+ let mut args = get_args_from_env_vars();\n+\n+ // Put the zero-th CLI argument (program name) first\n+ args.insert(0, cli_args.next().unwrap());\n+\n+ // .. and the rest at the end (includes --help and other CLI args)\n+ cli_args.for_each(|a| args.push(a));\n args\n } else {\n let mut cli_args = wild::args_os();\n \n // Read arguments from bats config file\n- let mut args = get_args_from_env_opts_var()\n- .unwrap_or_else(get_args_from_config_file)\n- .map_err(|_| \"Could not parse configuration file\")?;\n+ let mut args = match get_args_from_env_opts_var() {\n+ Some(result) => result,\n+ None => get_args_from_config_file(),\n+ }\n+ .map_err(|_| \"Could not parse configuration file\")?;\n \n // Selected env vars supersede config vars\n...[truncated]", "anchor_file": "src/bin/bat/app.rs", "intent": "feat: add paging to '-h' and '--help'\n\nFixes #1587\n\ncontinuation of #3432\n\nfeat: add paging to '-h' and '--help'\n\nchore: update changelog\n\nchore: add bats highlights\n\nchore: add custom help and version handling and allow configuring\n\nchore: format files\n\nUpdate main.rs\n\nMerge branch 'master' into master\n\nchore: bring back\n\nfeat: add theme options to help too\n\ncomplete\n\nchore: add entry\n\nMerge branch 'master' into feat/help-pager"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "3ecbd18e56eecc4f3c4da4176908c80cfff4ac3c", "candidate_corpus": {"base_commit": "3ecbd18e56eecc4f3c4da4176908c80cfff4ac3c", "type": "repo_at_base_commit"}, "gold": {"files": ["Cargo.toml"], "given_files": ["src/theme.rs"]}, "id": "a37d661fc06178e32fa250c5", "metadata": {"changed_files": ["Cargo.lock", "Cargo.toml", "src/theme.rs"], "created_at": "2025-10-31T06:50:20Z", "fix_commit": "ce856dbba7459eea728612f2de89de69896355ee", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 2, "deletions": 3, "is_test": false, "path": "Cargo.toml", "signals": ["gold_diff_mentions_anchor_module", "shared_changed_symbol", "shared_config_or_schema"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": [], "nonfatal_hits": {}}, "merged_at": "2025-11-03T18:06:34Z", "pr": 3464, "ripple_relation": ["gold_diff_mentions_anchor_module", "shared_changed_symbol", "shared_config_or_schema"], "source_pr": "https://github.com/sharkdp/bat/pull/3464"}, "query": {"anchor_diff": "@@ -288,7 +288,7 @@ fn color_scheme_from_system() -> Option {\n const PREFERENCES_FILE: &str = \"Library/Preferences/.GlobalPreferences.plist\";\n const STYLE_KEY: &str = \"AppleInterfaceStyle\";\n \n- let preferences_file = home::home_dir()\n+ let preferences_file = std::env::home_dir()\n .map(|home| home.join(PREFERENCES_FILE))\n .expect(\"Could not get home directory\");", "anchor_file": "src/theme.rs", "intent": "Update etcetera to 0.11; no longer depend on `home`; MSRV 1.87\n\nRelease 0.11 of `etcetera` requires MSRV 1.87, in which `std::env::home_dir` is no longer deprecated,\nhttps://github.com/rust-lang/rust/pull/137327.\n\nUpdate to that MSRV and to `etcetera`, and drop the dependency on the `home` crate just as `etcetera` 0.11 did.\n\nUpdate etcetera to 0.11; no longer depend on `home`; MSRV 1.87"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "c51cff896179264a7ff1a34910446cf21eedfb48", "candidate_corpus": {"base_commit": "c51cff896179264a7ff1a34910446cf21eedfb48", "type": "repo_at_base_commit"}, "gold": {"files": ["src/output.rs", "src/bin/bat/main.rs"], "given_files": ["src/controller.rs"]}, "id": "ab6ce66d4a23cc8020c9ea28", "metadata": {"changed_files": ["CHANGELOG.md", "src/bin/bat/main.rs", "src/controller.rs", "src/output.rs"], "created_at": "2025-10-28T11:21:00Z", "fix_commit": "1e4a4b765f4a1cad74f3a4204112268f3b303f2f", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 11, "deletions": 9, "is_test": false, "path": "src/output.rs", "signals": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}, {"additions": 19, "deletions": 16, "is_test": false, "path": "src/bin/bat/main.rs", "signals": ["gold_diff_mentions_anchor_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"src/bin/bat/main.rs": ["bat"], "src/output.rs": ["output"]}}, "merged_at": "2025-11-15T13:49:41Z", "pr": 3457, "ripple_relation": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol", "gold_diff_mentions_anchor_module"], "source_pr": "https://github.com/sharkdp/bat/pull/3457"}, "query": {"anchor_diff": "@@ -50,10 +50,12 @@ impl Controller<'_> {\n output_handle: Option<&mut OutputHandle<'_>>,\n mut handle_error: impl FnMut(&Error, &mut dyn Write),\n ) -> Result {\n- let mut output_type;\n+ // only create our own OutputType if no output handle was provided.\n+ #[allow(unused_mut)]\n+ let mut output_type_opt: Option = None;\n \n #[cfg(feature = \"paging\")]\n- {\n+ if output_handle.is_none() {\n use crate::input::InputKind;\n use std::path::Path;\n \n@@ -74,25 +76,35 @@ impl Controller<'_> {\n \n let wrapping_mode = self.config.wrapping_mode;\n \n- output_type = OutputType::from_mode(paging_mode, wrapping_mode, self.config.pager)?;\n+ output_type_opt = Some(OutputType::from_mode(\n+ paging_mode,\n+ wrapping_mode,\n+ self.config.pager,\n+ )?);\n }\n \n #[cfg(not(feature = \"paging\"))]\n- {\n- output_type = OutputType::stdout();\n+ if output_handle.is_none() {\n+ output_type_opt = Some(OutputType::stdout());\n }\n \n- let attached_to_pager = output_type.is_pager();\n+ let attached_to_pager = match (&output_handle, &output_type_opt) {\n+ (Some(_), _) => true,\n+ (None, Some(ot)) => ot.is_pager(),\n+ (None, None) => false,\n+ };\n+\n let stdout_identifier = if cfg!(windows) || attached_to_pager {\n None\n } else {\n clircle::Identifier::stdout()\n };\n \n- let mut writer = match output_handle {\n- Some(OutputHandle::FmtWrite(w)) => OutputHandle::FmtWrite(w),\n- Some(OutputHandle::IoWrite(w)) => OutputHandle::IoWrite(w),\n- None => output_type.handle()?,\n+ let mut writer = match (output_handle, &mut output_type_opt) {\n+ (Some(OutputHandle::FmtWrite(w)), _) => OutputHandle::FmtWrite(w),\n+ (Some(OutputHandle::IoWrite(w)), _) => OutputHandle::IoWrite(w),\n+ (None, Some(ot)) => ot.handle()?,\n+ (None, None) => unreachable!(\"No output handle and no output type available\"),\n };\n let mut no_errors: bool = true;\n let stderr = io::stderr();", "anchor_file": "src/controller.rs", "intent": "fix: `--list-themes` pagination\n\n### Fixes Issue: #3455 \n### Bug\n`bat --list-themes --pager=builtin` and `bat --list-themes --pager=less` hang after printing the first line (e.g., “Theme: 1337”). In iTerm2 the “:” prompt is hidden until resize/CR, input is in cooked mode, and display appears off-by-one.\n### Repro:\n`bat --list-themes --pager=builtin`\n`bat --list-themes --pager=less`\n### Root cause\n- controller was creating its own pager even when an OutputHandle was already provided by the caller which led to nested pagers and TTY state confusion, manifesting as a hang and terminal not restoring properly.\n- also treated stdout as “safe” when a pager was already attached, allowing clircle’s stdout identifier to be created in a pager context, which can block and contribute to the bad terminal state.\n### Changes\nOnly create `OutputType` when `output_handle.is_none()`, preventing a second pager from being started.\nadded `attached_to_pager` that is true when:\n\n- an external `OutputHandle` is provided, or\n- an internally created `OutputType` is a pager.\n\nRoute errors to the writer when `attached_to_pager`; otherwise use stderr.\nSet `stdout_identifier = None` when `attached_to_pager` (and on Windows); otherwise use `clircle::Identifier::stdout()`.\n\nfix --list-themes hang\n\nadded changelog\n\nchangelog\n\nFix --list-themes pager init so less stays interactive\n\nMerge branch 'master' into fix/list-themes-pager-hang\n\nlist-themes buffer added\n\nfix prefix\n\nchange imports"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "c51cff896179264a7ff1a34910446cf21eedfb48", "candidate_corpus": {"base_commit": "c51cff896179264a7ff1a34910446cf21eedfb48", "type": "repo_at_base_commit"}, "gold": {"files": ["src/controller.rs", "src/bin/bat/main.rs"], "given_files": ["src/output.rs"]}, "id": "e67a20f029dc5a9a4ffc9aae", "metadata": {"changed_files": ["CHANGELOG.md", "src/bin/bat/main.rs", "src/controller.rs", "src/output.rs"], "created_at": "2025-10-28T11:21:00Z", "fix_commit": "1e4a4b765f4a1cad74f3a4204112268f3b303f2f", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 22, "deletions": 10, "is_test": false, "path": "src/controller.rs", "signals": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 19, "deletions": 16, "is_test": false, "path": "src/bin/bat/main.rs", "signals": ["gold_diff_mentions_anchor_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"src/bin/bat/main.rs": ["bat", "bin"], "src/controller.rs": ["controller"]}}, "merged_at": "2025-11-15T13:49:41Z", "pr": 3457, "ripple_relation": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol"], "source_pr": "https://github.com/sharkdp/bat/pull/3457"}, "query": {"anchor_diff": "@@ -141,16 +141,18 @@ impl OutputType {\n //\n // For newer versions (530 or 558 on Windows), we omit '--no-init' as it\n // is not needed anymore.\n- match retrieve_less_version(&pager.bin) {\n- None => {\n- p.arg(\"--no-init\");\n- }\n- Some(LessVersion::Less(version))\n- if (version < 530 || (cfg!(windows) && version < 558)) =>\n- {\n- p.arg(\"--no-init\");\n+ if single_screen_action == SingleScreenAction::Quit {\n+ match retrieve_less_version(&pager.bin) {\n+ None => {\n+ p.arg(\"--no-init\");\n+ }\n+ Some(LessVersion::Less(version))\n+ if (version < 530 || (cfg!(windows) && version < 558)) =>\n+ {\n+ p.arg(\"--no-init\");\n+ }\n+ _ => {}\n }\n- _ => {}\n }\n } else {\n p.args(args);", "anchor_file": "src/output.rs", "intent": "fix: `--list-themes` pagination\n\n### Fixes Issue: #3455 \n### Bug\n`bat --list-themes --pager=builtin` and `bat --list-themes --pager=less` hang after printing the first line (e.g., “Theme: 1337”). In iTerm2 the “:” prompt is hidden until resize/CR, input is in cooked mode, and display appears off-by-one.\n### Repro:\n`bat --list-themes --pager=builtin`\n`bat --list-themes --pager=less`\n### Root cause\n- controller was creating its own pager even when an OutputHandle was already provided by the caller which led to nested pagers and TTY state confusion, manifesting as a hang and terminal not restoring properly.\n- also treated stdout as “safe” when a pager was already attached, allowing clircle’s stdout identifier to be created in a pager context, which can block and contribute to the bad terminal state.\n### Changes\nOnly create `OutputType` when `output_handle.is_none()`, preventing a second pager from being started.\nadded `attached_to_pager` that is true when:\n\n- an external `OutputHandle` is provided, or\n- an internally created `OutputType` is a pager.\n\nRoute errors to the writer when `attached_to_pager`; otherwise use stderr.\nSet `stdout_identifier = None` when `attached_to_pager` (and on Windows); otherwise use `clircle::Identifier::stdout()`.\n\nfix --list-themes hang\n\nadded changelog\n\nchangelog\n\nFix --list-themes pager init so less stays interactive\n\nMerge branch 'master' into fix/list-themes-pager-hang\n\nlist-themes buffer added\n\nfix prefix\n\nchange imports"}, "repo": "sharkdp/bat", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "40c22f4bc57d4ea6aa323928c037c947890fe81c", "candidate_corpus": {"base_commit": "40c22f4bc57d4ea6aa323928c037c947890fe81c", "type": "repo_at_base_commit"}, "gold": {"files": ["router_test.go"], "given_files": ["router.go"]}, "id": "71d8389aaa75d8d1ab81a1cc", "metadata": {"changed_files": ["router.go", "router_test.go"], "created_at": "2026-10-05T23:10:00Z", "fix_commit": "296824015d4a6345531fa71e9233fd42879f2c69", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 25, "deletions": 0, "is_test": true, "path": "router_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"router_test.go": ["router"]}}, "merged_at": "2026-10-06T03:26:19Z", "pr": 3160, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/labstack/echo/pull/3160"}, "query": {"anchor_diff": "@@ -255,7 +255,7 @@ func (m *routeMethods) set(method string, r *routeMethod) {\n \t\tif m.anyOther == nil {\n \t\t\tm.anyOther = make(map[string]*routeMethod)\n \t\t}\n-\t\tif r.handler == nil {\n+\t\tif r == nil || r.handler == nil { // Router.Remove passes nil\n \t\t\tdelete(m.anyOther, method)\n \t\t} else {\n \t\t\tm.anyOther[method] = r", "anchor_file": "router.go", "intent": "fix(router): removing a route with a custom method panics\n\n`Router.Remove` panics with a nil pointer dereference for a route registered with a custom method, for example `e.Add(\"PURGE\", \"/cache\", h)` followed by `e.Router().Remove(\"PURGE\", \"/cache\")`. `ConcurrentRouter.Remove` delegates to it, so it panics too.\n\n**Cause:** `Remove` clears the handler with `setHandler(method, nil)`. Methods with their own field (GET, POST, …) just set it to nil. Custom methods fall through to the `default` branch of `routeMethods.set`, which read `r.handler` on the nil route.\n\n**Fix:** treat a nil route like a nil handler and delete the `anyOther` entry. `Remove` is the only caller that passes nil.\n\n**Test:** `TestDefaultRouter_RemoveCustomMethod` covers two cases:\n- Removing a custom-method route from a path that keeps its GET route: the Routes list is updated, a later PURGE request gets 405, and PURGE is gone from the Allow header.\n- Removing the only route on a path: a later request gets 404.\n\nIt panics on master and passes here. `go test -race ./...`, `go vet`, `staticcheck` and `golint` pass.\n\nv4 has no `Router.Remove`, so this is v5 only.\n\nfix(router): removing a route with a custom method panics\n\ntest(router): assert the exact Allow header after removing a custom method\n\ntest(router): match the Allow header order after removing a custom method"}, "repo": "labstack/echo", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "320fe67b1e4eae941cec6b185eddd07a2ac4765b", "candidate_corpus": {"base_commit": "320fe67b1e4eae941cec6b185eddd07a2ac4765b", "type": "repo_at_base_commit"}, "gold": {"files": ["router_test.go", "echo_test.go"], "given_files": ["router.go"]}, "id": "65760bd68c70c2f62a6a1aba", "metadata": {"changed_files": ["echo_test.go", "router.go", "router_test.go"], "created_at": "2026-10-05T22:10:34Z", "fix_commit": "be0800562a0b6760d570b19fc372c3aa3c378978", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 40, "deletions": 0, "is_test": true, "path": "router_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 17, "deletions": 0, "is_test": true, "path": "echo_test.go", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"echo_test.go": ["echo"], "router_test.go": ["router"]}}, "merged_at": "2026-10-06T02:52:15Z", "pr": 3158, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/labstack/echo/pull/3158"}, "query": {"anchor_diff": "@@ -582,6 +582,16 @@ func optionsMethodHandler(allowMethods string) func(c Context) error {\n \t}\n }\n \n+// growParamValues replaces the context's pvalues when the context was created (and pooled) before a route with more\n+// path params was added, so Find can set values by index. Values already set during this Find are kept and the\n+// context keeps the new slice for later requests.\n+func (r *Router) growParamValues(ctx *context, paramValues []string) []string {\n+\tgrown := make([]string, *r.echo.maxParam)\n+\tcopy(grown, paramValues)\n+\tctx.pvalues = grown\n+\treturn grown\n+}\n+\n // Find lookup a handler registered for method and path. It also parses URL for path\n // parameters and load them into context.\n //\n@@ -730,6 +740,9 @@ func (r *Router) Find(method, path string, c Context) {\n \t\t\t\ti = l\n \t\t\t}\n \n+\t\t\tif paramIndex >= len(paramValues) {\n+\t\t\t\tparamValues = r.growParamValues(ctx, paramValues)\n+\t\t\t}\n \t\t\tparamValues[paramIndex] = search[:i]\n \t\t\tparamIndex++\n \t\t\tsearch = search[i:]\n@@ -742,6 +755,9 @@ func (r *Router) Find(method, path string, c Context) {\n \t\tif child := currentNode.anyChild; child != nil {\n \t\t\t// If any node is found, use remaining path for paramValues\n \t\t\tcurrentNode = child\n+\t\t\tif currentNode.paramsCount > len(paramValues) {\n+\t\t\t\tparamValues = r.growParamValues(ctx, paramValues)\n+\t\t\t}\n \t\t\tparamValues[currentNode.paramsCount-1] = search\n \n \t\t\t// update indexes/search in case we need to backtrack when no handler match is found", "anchor_file": "router.go", "intent": "fix(router): grow param values for contexts created before a route with more params (v4)\n\nAdding a route with path params after Echo has served requests can panic with `index out of range [0] with length 0`. It happens in sequential, single-goroutine use:\n- A late **any** route (`/files/*`) panics in every v4 release: in `Router.Find`, or already in `Context.Reset` from v4.1.12 to v4.11.x.\n- A late **param** route (`/users/:id`) wrongly returned 404 up to v4.1.11. From v4.1.12 to v4.11.x it panics in `Context.Reset`, on the next request of any kind.\n- From v4.12.0 (after #2611), late param and any routes panic in `Router.Find`, on requests whose routing reaches the late param or any node. That includes some 404s and 405s.\n\n**Repro:** register `GET /static`, serve `/static`, register `GET /users/:id`, serve `/users/42`.\n\n**Cause:** pooled contexts keep the `pvalues` length they were created with (`*e.maxParam` at the time), and `Router.Find` sets values by index. #2611 fixed `SetParamNames`/`SetParamValues` and `Reset`, but not `Find`.\n\n**Fix:** when `Find` is about to set a param or any value past the context's `pvalues` length, it grows the slice to `*r.echo.maxParam`, keeps the values already set, and stores it on the context. Static routes never reach these branches.\n\nThis does not make it safe to add routes concurrently with serving. That is still unsupported in v4, as discussed in #1705.\n\n**Cost:** 20 interleaved rounds against v4 show +0.9% geomean on router benchmarks, with 0 allocs. Static routes are unchanged. Param-heavy routes rise up to about +2.8%, which is about 0.5–1.4 ns per param lookup. This was the cheapest of three placements measured (top of `Find`: +1.1%; `Reset` with `clear()`: +2.6%).\n\n**Tests:**\n- `TestEchoAddParamRouteAfterServing` is the end-t\n...[truncated]"}, "repo": "labstack/echo", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "40c22f4bc57d4ea6aa323928c037c947890fe81c", "candidate_corpus": {"base_commit": "40c22f4bc57d4ea6aa323928c037c947890fe81c", "type": "repo_at_base_commit"}, "gold": {"files": ["router_test.go", "echo_test.go"], "given_files": ["router.go"]}, "id": "723e442ddddcf3681eb592c3", "metadata": {"changed_files": ["echo_test.go", "router.go", "router_test.go"], "created_at": "2026-10-05T22:10:31Z", "fix_commit": "4f7bea5d2ad253d2d0fddb1382ae25be040a3d8b", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 50, "deletions": 0, "is_test": true, "path": "router_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 30, "deletions": 0, "is_test": true, "path": "echo_test.go", "signals": ["gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"echo_test.go": ["echo"], "router_test.go": ["router"]}}, "merged_at": "2026-10-06T02:52:10Z", "pr": 3157, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/labstack/echo/pull/3157"}, "query": {"anchor_diff": "@@ -15,8 +15,11 @@ import (\n // Router is interface for routing request contexts to registered routes.\n //\n // Contract between Echo/Context instance and the router:\n-// - all routes must be added through methods on echo.Echo instance.\n-// Reason: Echo instance uses RouteInfo.Params() length to allocate slice for paths parameters (see `Echo.contextPathParamAllocSize`).\n+// - all routes should be added through methods on echo.Echo instance.\n+// Reason: Echo instance uses RouteInfo.Parameters length to allocate slice for paths parameters (see `Echo.contextPathParamAllocSize`),\n+// so Contexts are created with enough capacity.\n+// - Router.Route must handle a Context whose PathValues capacity is smaller than the maximum path parameter count\n+// of its routes (for example, when a route was added after the Context was created, or not through echo.Echo).\n // - Router must populate Context during Router.Route call with:\n // - Context.InitializeRoute (IMPORTANT! to reduce allocations use same slice that c.PathValues() returns)\n // - Optionally can set additional information to Context with Context.Set\n@@ -916,7 +919,11 @@ var optionsMethodHandler = func(c *Context) error {\n func (r *DefaultRouter) Route(c *Context) HandlerFunc {\n \tpathValues := c.PathValues()\n \tif cap(pathValues) < r.maxPathParamsLength {\n-\t\tpathValues = make(PathValues, 0, r.maxPathParamsLength)\n+\t\t// The Context has less capacity than this router's routes need, for example because it was created before a\n+\t\t// route with more params was added. Grow its PathValues at full length so values can be set by index below. The\n+\t\t// Context keeps the new slice, so later requests do not grow it again unless a route with more params is added.\n+\t\t*c.pathValues = make(PathValues, r.maxPathParamsLength)\n+\t\tpathValues = *c.pathValues\n \t} else {\n \t\tpathValues = pathValues[0:cap(pathValues)] // resize slice to maximum capacity so we can index set values\n \t}", "anchor_file": "router.go", "intent": "fix(router): grow PathValues for contexts created before a route with more params\n\nAdding a route with more path params after Echo has served requests panics with `index out of range [0] with length 0` on the next request that matches it. This happens with both `DefaultRouter` and `ConcurrentRouter`, even though `NewConcurrentRouter` says routes can be added after the server has started. The faulty line is in every v5 release (v5.0.0 through v5.4.0).\n\n**Repro:** register `GET /static`, serve `/static`, register `GET /users/:id`, serve `/users/42`.\n\n**Cause:** pooled `Context`s keep the `PathValues` capacity they were created with. `DefaultRouter.Route` already detected the short capacity, but it allocated a zero-length slice (`make(PathValues, 0, max)`) and then set values by index. The same branch is reached by Contexts created without an Echo and when routes are added through `Router().Add` directly; both panic on master too.\n\n**Fix:** grow the Context's `PathValues` at full length in that existing branch. The Context keeps the new slice, so it is grown once, whatever route the request matches (static, param, 404 or 405), until a route with even more params is added. The `Router` contract comment now says that `Route` must handle a Context with a smaller capacity, and that adding routes through Echo is what keeps Contexts sized up front.\n\n**Cost:** the change only touches the branch that already handled short capacity, so steady state is unchanged:\n- `ServeHTTP_*`, `Echo*API` and `Router*API` benchmarks: 20 interleaved rounds against master show no regression, and allocations per operation are unchanged.\n- After its first request, a stale Context allocates the same as a fresh one for static, 404, 405 and param routes. On master, when routes have 2 or more params, a st\n...[truncated]"}, "repo": "labstack/echo", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "f085ffbe8f99de165bd920746920000ab56bd6bc", "candidate_corpus": {"base_commit": "f085ffbe8f99de165bd920746920000ab56bd6bc", "type": "repo_at_base_commit"}, "gold": {"files": ["bind_test.go"], "given_files": ["bind.go"]}, "id": "49dbcc448bef9d2f035180a6", "metadata": {"changed_files": ["bind.go", "bind_test.go"], "created_at": "2026-10-05T18:21:59Z", "fix_commit": "320fe67b1e4eae941cec6b185eddd07a2ac4765b", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 187, "deletions": 2, "is_test": true, "path": "bind_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"bind_test.go": ["bind"]}}, "merged_at": "2026-10-05T19:22:05Z", "pr": 3156, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/labstack/echo/pull/3156"}, "query": {"anchor_diff": "@@ -22,6 +22,13 @@ type Binder interface {\n }\n \n // DefaultBinder is the default implementation of the Binder interface.\n+// For path, query, header, and form binding, time.Time and *time.Time fields (not slices)\n+// may use a format tag: \"date-time\" uses the standard RFC3339 decoding, \"date-time-local\"\n+// accepts \"2006-01-02T15:04:05\" with optional fractional seconds, \"date\" accepts\n+// \"2006-01-02\", and other values specify Go time layouts. \"date\", \"date-time-local\", and\n+// layouts without a timezone give UTC times. JSON and XML decoding do not use this tag.\n+// HTML datetime-local inputs omit seconds by default, so bind them with a Go layout\n+// such as \"2006-01-02T15:04\" instead of \"date-time-local\".\n type DefaultBinder struct{}\n \n // BindUnmarshaler is the interface used to wrap the UnmarshalParam method.\n@@ -42,10 +49,11 @@ type bindMultipleUnmarshaler interface {\n // BindPathParams binds path params to bindable object\n //\n // Time format support: time.Time fields can use `format` tags to specify custom parsing layouts.\n-// Example: `param:\"created\" format:\"2006-01-02T15:04\"` for datetime-local format\n+// Example: `form:\"created\" format:\"2006-01-02T15:04\"` for HTML datetime-local input\n // Example: `param:\"date\" format:\"2006-01-02\"` for date format\n // Uses Go's standard time format reference time: Mon Jan 2 15:04:05 MST 2006\n-// Works with form data, query parameters, and path parameters (not JSON body)\n+// OpenAPI format names \"date-time\", \"date-time-local\" and \"date\" are also supported (see DefaultBinder)\n+// Works with form data, query parameters, headers, and path parameters (not JSON body)\n // Falls back to default time.Time parsing if no format tag is specified\n func (b *DefaultBinder) BindPathParams(c Context, i interface{}) error {\n \tnames := c.ParamNames()\n@@ -387,10 +395,19 @@ func unmarshalInputToField(valueKind reflect.Kind, val string, field reflect.Val\n \n \tfieldIValue := field.Addr().Interface()\n \n-\t// Handle time.Time with custom format tag\n-\tif formatTag != \"\" {\n+\t// date-time uses the same TextUnmarshaler as an untagged time.Time.\n+\tif formatTag != \"\" && formatTag != \"date-time\" {\n \t\tif _, isTime := fieldIValue.(*time.Time); isTime {\n-\t\t\tt, err := time.Parse(formatTag, val)\n+\t\t\t// OpenAPI dates and local date-times have no timezone. time.Parse assigns UTC,\n+\t\t\t// as it does for custom layouts without timezone information.\n+\t\t\tlayout := formatTag\n+\t\t\tswitch formatTag {\n+\t\t\tcase \"date\":\n+\t\t\t\tlayout = \"2006-01-02\"\n+\t\t\tcase \"date-time-local\":\n+\t\t\t\tlayout = \"2006-01-02T15:04:05\"\n+\t\t\t}\n+\t\t\tt, err := time.Parse(layout, val)\n \t\t\tif err != nil {\n \t\t\t\treturn true, err\n \t\t\t}", "anchor_file": "bind.go", "intent": "fix(bind): honor OpenAPI date, date-time and date-time-local format tags (v4)\n\nBackport of #3145 to v4.\n\nSwag and OpenAPI put format names such as `format:\"date-time\"` on `time.Time` fields. Since v4.14.0 added `format` tag support, the binder has treated those names as Go time layouts, so valid input failed to bind. Before v4.14.0 the tag was ignored, so RFC3339 values bound to swag-annotated `format:\"date-time\"` fields. That case broke on upgrade.\n\n- `date-time` uses the same RFC3339 decoding as an untagged `time.Time`, which restores the pre-v4.14.0 behavior.\n- `date-time-local` accepts `2006-01-02T15:04:05` with optional fractional seconds, rejects time-zone suffixes, and assigns UTC.\n- `date` accepts `2006-01-02` and assigns UTC.\n- For `date-time-local` and `date`, zoned RFC3339 values bound before v4.14.0 only because the tag was ignored. They stay rejected, as the OpenAPI definitions require.\n- Parsing uses Go's `time` package, so it is as lenient as untagged `time.Time` binding (for example, it accepts a comma before fractional seconds).\n- Other `format` values are still Go layouts. Slice fields never used the tag and are unchanged.\n\nCompared with current v4, the only inputs that bound before and now fail are the literal strings `date-time`, `date-time-local`, and `date`, which parsed to `0000-01-01T00:00:00Z`.\n\nThe tests are ported from #3145 and adapted to the v4 binder API. They cover path, query, header, form, and multipart sources, scalar and pointer fields, JSON decoding, custom types, the literal format names, and slice fields. Without the fix, 53 of the new cases fail. With it, `go test -race ./...`, `staticcheck`, and `golint` pass.\n\nThe `BindPathParams` doc now mentions the OpenAPI names and headers, and its HTML `datetime-local` example uses a `form`\n...[truncated]"}, "repo": "labstack/echo", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "99c395d846e079d4cffd29de9298d1dd829e8b04", "candidate_corpus": {"base_commit": "99c395d846e079d4cffd29de9298d1dd829e8b04", "type": "repo_at_base_commit"}, "gold": {"files": ["context_test.go"], "given_files": ["context.go"]}, "id": "c6ae8ba4b1dd9d73f8d1ae9c", "metadata": {"changed_files": ["context.go", "context_test.go"], "created_at": "2026-10-04T13:21:14Z", "fix_commit": "8fd0e184dd390ffdf082f5eda247c3ab41d5d290", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 130, "deletions": 1, "is_test": true, "path": "context_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"context_test.go": ["context"]}}, "merged_at": "2026-10-12T15:06:45Z", "pr": 3152, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/labstack/echo/pull/3152"}, "query": {"anchor_diff": "@@ -5,6 +5,7 @@ package echo\n \n import (\n \t\"bytes\"\n+\tstdContext \"context\"\n \t\"encoding/xml\"\n \t\"errors\"\n \t\"fmt\"\n@@ -460,6 +461,10 @@ func (c *Context) Bind(i any) error {\n \treturn c.echo.Binder.Bind(c, i)\n }\n \n+type validatorCtx interface {\n+\tValidateCtx(ctx stdContext.Context, i any) error\n+}\n+\n // Validate validates provided `i`. It is usually called after `Context#Bind()`.\n // Validator must be registered using `Echo#Validator`.\n func (c *Context) Validate(i any) error {\n@@ -469,6 +474,27 @@ func (c *Context) Validate(i any) error {\n \treturn c.echo.Validator.Validate(i)\n }\n \n+// ValidateCtx validates i using the current request's context. If the registered\n+// Validator implements ValidateCtx(context.Context, any) error, that method is\n+// called instead of Validate. Otherwise, Validate is called.\n+//\n+// The validator must still implement Validate to satisfy the Validator interface.\n+// Wrappers that embed a context-aware validator must implement ValidateCtx if they\n+// need to preserve checks performed by their own Validate method.\n+//\n+// If there is no request, context.Background() is used. Cancellation and deadlines\n+// are passed to the validator; the validator is responsible for honoring them.\n+func (c *Context) ValidateCtx(i any) error {\n+\tif v, ok := c.echo.Validator.(validatorCtx); ok {\n+\t\tctx := stdContext.Background()\n+\t\tif req := c.Request(); req != nil {\n+\t\t\tctx = req.Context()\n+\t\t}\n+\t\treturn v.ValidateCtx(ctx, i)\n+\t}\n+\treturn c.Validate(i)\n+}\n+\n // Render renders a template with data and sends a text/html response with status\n // code. Renderer must be registered using `Echo.Renderer`.\n func (c *Context) Render(code int, name string, data any) (err error) {", "anchor_file": "context.go", "intent": "feat(context): add ValidateCtx\n\nThis adds c.ValidateCtx(v) to pass the request context to the validator, as discussed in [#2399](https://github.com/labstack/echo/discussions/2399). If the validator doesn't implement ValidateCtx, it calls Validate instead.\n\nI left c.Validate(v) unchanged. Making it call ValidateCtx automatically could skip a wrapper's own validation when it embeds another validator with that method.\n\nfeat: pass request context to context-aware validators\n\nfeat: make context-aware validation explicit\n\ntest(context): cover request replacement in ValidateCtx"}, "repo": "labstack/echo", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "eadbef28df3b293a7e7b39977ac949c5907fa559", "candidate_corpus": {"base_commit": "eadbef28df3b293a7e7b39977ac949c5907fa559", "type": "repo_at_base_commit"}, "gold": {"files": ["route.go"], "given_files": ["router.go"]}, "id": "2b23f85b3d2c198587fc2668", "metadata": {"changed_files": ["route.go", "route_path.go", "route_syntax_test.go", "router.go"], "created_at": "2026-09-29T20:46:08Z", "fix_commit": "af07b69b44c0688d03208dda296f5694de9476e4", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 22, "deletions": 16, "is_test": false, "path": "route.go", "signals": ["same_component", "anchor_diff_mentions_gold_module", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_stem_hint"], "nonfatal_hits": {"route.go": ["route"]}}, "merged_at": "2026-09-30T01:00:13Z", "pr": 3133, "ripple_relation": ["same_component", "anchor_diff_mentions_gold_module", "gold_diff_mentions_anchor_module", "shared_changed_symbol"], "source_pr": "https://github.com/labstack/echo/pull/3133"}, "query": {"anchor_diff": "@@ -8,6 +8,8 @@ import (\n \t\"errors\"\n \t\"net/http\"\n \t\"net/url\"\n+\t\"slices\"\n+\t\"strings\"\n )\n \n // Router is interface for routing request contexts to registered routes.\n@@ -167,12 +169,13 @@ type node struct {\n \t// scLabels holds the first byte (label) of each staticChildren entry in the\n \t// same order. Scanning this contiguous byte slice during routing is more\n \t// cache-friendly than dereferencing each *node to read its label.\n-\tscLabels []byte\n-\tparamsCount int\n-\tkind kind\n-\tlabel byte\n-\tisLeaf bool\n-\tisHandler bool\n+\tscLabels []byte\n+\tparamsCount int\n+\tkind kind\n+\tlabel byte\n+\tisLeaf bool\n+\tisHandler bool\n+\thasColonChild bool\n }\n \n type kind uint8\n@@ -387,40 +390,27 @@ func (r *DefaultRouter) Remove(method string, path string) error {\n \t\treturn errors.New(\"router has no routes to remove\")\n \t}\n \n-\tif path == \"\" {\n-\t\tpath = \"/\"\n-\t}\n-\tif path[0] != '/' {\n-\t\tpath = \"/\" + path\n-\t}\n+\tpath = normalizePathSlash(path)\n+\ttreePath, paramMarkers := routeTreePath(parseRoutePath(path))\n \n \tvar nodeToRemove *node\n-\tprefixLen := 0\n+\tsearch := treePath\n+\tsearchOffset := 0\n \tfor {\n-\t\tif currentNode.originalPath == path && currentNode.isHandler {\n-\t\t\tnodeToRemove = currentNode\n+\t\tif !strings.HasPrefix(search, currentNode.prefix) {\n \t\t\tbreak\n \t\t}\n-\t\tif currentNode.kind == staticKind {\n-\t\t\tprefixLen = prefixLen + len(currentNode.prefix)\n-\t\t} else {\n-\t\t\tprefixLen = len(currentNode.originalPath)\n-\t\t}\n+\t\tsearch = search[len(currentNode.prefix):]\n+\t\tsearchOffset += len(currentNode.prefix)\n \n-\t\tif prefixLen >= len(path) {\n+\t\tif search == \"\" {\n+\t\t\tif currentNode.isHandler {\n+\t\t\t\tnodeToRemove = currentNode\n+\t\t\t}\n \t\t\tbreak\n \t\t}\n \n-\t\tnext := path[prefixLen]\n-\t\tswitch next {\n-\t\tcase paramLabel:\n-\t\t\tcurrentNode = currentNode.paramChild\n-\t\tcase anyLabel:\n-\t\t\tcurrentNode = currentNode.anyChild\n-\t\tdefault:\n-\t\t\tcurrentNode = currentNode.findStaticChild(next)\n-\t\t}\n-\n+\t\tcurrentNode = currentNode.findChildWithLabel(search[0], slices.Contains(paramMarkers, searchOffset))\n \t\tif currentNode == nil {\n \t\t\tbreak\n \t\t}\n@@ -434,18 +424,23 @@ func (r *DefaultRouter) Remove(method string, path string) error {\n \t\treturn errors.New(\"could not find route to remove by given path\")\n \t}\n \n-\tif mh := nodeToRemove.methods.find(method, false, false); mh == nil {\n+\t// routes with different param names can share a node, so the path must be the one registered for this method\n+\tmh := nodeToRemove.methods.find(method, false, false)\n+\tif mh == nil || mh.Path != path {\n \t\treturn errors.New(\"could not find route to remove by given path and method\")\n \t}\n-\tnodeToRemove.setHandler(method, nil)\n \n-\tvar rIndex int\n+\trIndex := -1\n \tfor i, rr := range r.routes {\n-\t\tif rr.Method == method && rr.Path == path {\n+\t\tif rr.Method == method && rr.Path == mh.orgRouteInfo.Path {\n \t\t\trIndex = i\n \t\t\tbreak\n \t\t}\n \t}\n+\tif rIndex < 0 {\n+\t\treturn errors.New(\"could not find route to remove by given path and method\")\n+\t}\n+\tnodeToRemove.setHandler(method, nil)\n \tr.routes = append(r.routes[:rIndex], r.routes[rIndex+1:]...)\n \n \tif !nodeToRemove.isHandler && nodeToRemove.isLeaf {\n@@ -467,6 +462,9 @@ func (r *DefaultRouter) Remove(method string, path string) error {\n \t\t\t\t}\n \t\t\t\tparent.staticChildren = append(parent.staticChildren[:index], parent.staticChildren[index+1:]...)\n \t\t\t\tparent.scLabels = append(parent.scLabels[:index], parent.scLabels[index+1:]...)\n+\t\t\t\tif current.label == ':' {\n+\t\t\t\t\tparent.hasColonChild = false\n+\t\t\t\t}\n \t\t\tcase paramKind:\n \t\t\t\tparent.paramChild = nil\n \t\t\tcase anyKind:\n@@ -535,72 +533,48 @@ func (r *DefaultRouter) Add(route Route) (RouteInfo, error) {\n \t\theadH = wrapHeadHandler(h)\n \t}\n \n-\tparamNames := make([]string, 0)\n-\t// Positions of parameter markers after names are removed. Literal colons\n-\t// remain ordinary path bytes, so no sentinel byte is reserved.\n-\tparamMarkers := make([]int, 0)\n-\toriginalPath := path\n-\twasAdded := false\n-\tvar ri RouteInfo\n-\tfor i, lcpIndex := 0, len(path); i < lcpIndex; i++ {\n-\t\tif path[i] == paramLabel {\n-\t\t\tif i > 0 && path[i-1] == '\\\\' {\n-\t\t\t\tpath = path[:i-1] + path[i:]\n-\t\t\t\ti--\n-\t\t\t\tlcpIndex--\n-\t\t\t\tcontinue\n-\t\t\t}\n-\t\t\tj := i + 1\n-\n-\t\t\tr.insert(staticKind, path[:i], method, routeMethod{RouteInfo: &RouteInfo{Method: method}}, paramMarkers)\n-\t\t\tfor ; i < lcpIndex && path[i] != '/'; i++ {\n-\t\t\t}\n-\n-\t\t\tparamNames = append(paramNames, path[j:i])\n-\t\t\tparamMarkers = append(paramMarkers, j-1)\n-\t\t\tpath = path[:j] + path[i:]\n-\t\t\ti, lcpIndex = j, len(path)\n-\n-\t\t\tif i == lcpIndex {\n-\t\t\t\t// path node is last fragment of route path. ie. `/users/:id`\n-\t\t\t\tri = route.ToRouteInfo(paramNames)\n-\t\t\t\trm := routeMethod{\n-\t\t\t\t\tRouteInfo: &RouteInfo{Method: method, Path: originalPath, Parameters: paramNames, Name: route.Name},\n-\t\t\t\t\thandler: h,\n-\t\t\t\t\torgRouteInfo: ri,\n-\t\t\t\t\twrappedHeadHandler: headH,\n-\t\t\t\t}\n-\t\t\t\tr.insert(paramKind, path[:i], method, rm, paramMarkers)\n-\t\t\t\twasAdded = true\n-\t\t\t\tbreak\n-\t\t\t} else {\n-\t\t\t\tr.insert(paramKind, path[:i], method, routeMethod{RouteInfo: &RouteInfo{Method: method}}, paramMarkers)\n-\t\t\t}\n-\t\t} else if path[i] == anyLabel {\n-\t\t\tr.insert(staticKind, path[:i], method, routeMethod{RouteInfo: &RouteInfo{Method: method}}, paramMarkers)\n+\tparts := parseRoutePath(path)\n+\tvar paramNames []string\n+\tfor _, part := range parts {\n+\t\tif part.kind == paramKind {\n+\t\t\tparamNames = append(paramNames, part.value)\n+\t\t} else if part.kind == anyKind {\n \t\t\tparamNames = append(paramNames, \"*\")\n-\t\t\tri = route.ToRouteInfo(paramNames)\n-\t\t\trm := routeMethod{\n-\t\t\t\tRouteInfo: &RouteInfo{Method: method, Path: originalPath, Parameters: paramNames, Name: route.Name},\n-\t\t\t\thandler: h,\n-\t\t\t\torgRouteInfo: ri,\n-\t\t\t\twrappedHeadHandler: headH,\n...[truncated]", "anchor_file": "router.go", "intent": "fix(router): share route syntax across routing operations\n\n## Summary\n\nFollow-up to #3113. Three route-syntax bugs remained after it: a literal `\\:` after a parameter was swallowed into the parameter name, `Remove` could not find escaped-colon routes, and reverse routing dropped the literal verb.\n\n- **One route-syntax scanner** for registration, removal and reverse routing. An escaped colon after a parameter starts an inline verb (`/:name\\:cancel`) when the rest of that path segment is static. Other escaped colons after a parameter keep their older meaning as part of the parameter name.\n- **Inline verb matching.** At a param node with an inline verb child, the value first ends at a literal colon where the verb can match. If that route fails (path or method), the same param node is retried with the next split and finally the whole segment before routing backtracks to its parent. Static > param > any priority, group middleware and catch-all routes are unaffected by a failed split. A failed wildcard below a split keeps backtracking, so other routes below the split and then the next split are still tried.\n- **Linear time.** Split candidates are scanned once per segment, so a request with many colons costs O(path length × longest registered verb). A 1 MB path of colons routes in about 15 ms.\n- **Leaf params keep working.** When the inline verb child is a param node's only child, a value without a split still takes the rest of the path, so `GET /files/:path` next to `POST /files/:name\\:upload` still matches `/files/a/b`.\n- **Remove** finds the route by tree path and checks that the path is the one registered for that method.\n\n## Compatibility notes (release notes)\n\n- `/x/:id\\:y` now registers parameter `id` and a literal `:y`. Before, it registered one parameter named `id\\:y`\n...[truncated]"}, "repo": "labstack/echo", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "eadbef28df3b293a7e7b39977ac949c5907fa559", "candidate_corpus": {"base_commit": "eadbef28df3b293a7e7b39977ac949c5907fa559", "type": "repo_at_base_commit"}, "gold": {"files": ["router.go"], "given_files": ["route.go"]}, "id": "8659e17baec68065b0be0c93", "metadata": {"changed_files": ["route.go", "route_path.go", "route_syntax_test.go", "router.go"], "created_at": "2026-09-29T20:46:08Z", "fix_commit": "af07b69b44c0688d03208dda296f5694de9476e4", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 147, "deletions": 107, "is_test": false, "path": "router.go", "signals": ["same_component", "anchor_diff_mentions_gold_module", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_stem_hint"], "nonfatal_hits": {"router.go": ["router"]}}, "merged_at": "2026-09-30T01:00:13Z", "pr": 3133, "ripple_relation": ["same_component", "anchor_diff_mentions_gold_module", "gold_diff_mentions_anchor_module", "shared_changed_symbol"], "source_pr": "https://github.com/labstack/echo/pull/3133"}, "query": {"anchor_diff": "@@ -9,6 +9,7 @@ import (\n \t\"fmt\"\n \t\"reflect\"\n \t\"runtime\"\n+\t\"strings\"\n )\n \n // Route contains information to adding/registering new route with the router.\n@@ -81,24 +82,29 @@ func (r RouteInfo) Clone() RouteInfo {\n // Reverse reverses route to URL string by replacing path parameters with given params values.\n func (r RouteInfo) Reverse(pathValues ...any) string {\n \turi := new(bytes.Buffer)\n-\tln := len(pathValues)\n-\tn := 0\n-\tfor i, l := 0, len(r.Path); i < l; i++ {\n-\t\thasBackslash := r.Path[i] == '\\\\'\n-\t\tif hasBackslash && i+1 < l && r.Path[i+1] == ':' {\n-\t\t\ti++ // backslash before colon escapes that colon. in that case skip backslash\n-\t\t}\n-\t\tif n < ln && (r.Path[i] == anyLabel || (!hasBackslash && r.Path[i] == paramLabel)) {\n-\t\t\t// in case of `*` wildcard or `:` (unescaped colon) param we replace everything till next slash or end of path\n-\t\t\tfor ; i < l && r.Path[i] != '/'; i++ {\n+\tnextValue := 0\n+\twalkRoutePath(r.Path, func(part routePathPart) {\n+\t\tswitch part.kind {\n+\t\tcase staticKind:\n+\t\t\turi.WriteString(part.value)\n+\t\tcase paramKind:\n+\t\t\tif nextValue < len(pathValues) {\n+\t\t\t\tfmt.Fprint(uri, pathValues[nextValue])\n+\t\t\t\tnextValue++\n+\t\t\t} else {\n+\t\t\t\t// placeholder for a missing value. An escaped colon in a param name is written without its backslash.\n+\t\t\t\turi.WriteByte(paramLabel)\n+\t\t\t\turi.WriteString(strings.ReplaceAll(part.value, `\\:`, \":\"))\n+\t\t\t}\n+\t\tcase anyKind:\n+\t\t\tif nextValue < len(pathValues) {\n+\t\t\t\tfmt.Fprint(uri, pathValues[nextValue])\n+\t\t\t\tnextValue++\n+\t\t\t} else {\n+\t\t\t\turi.WriteString(strings.ReplaceAll(part.value, `\\:`, \":\"))\n \t\t\t}\n-\t\t\tfmt.Fprintf(uri, \"%v\", pathValues[n])\n-\t\t\tn++\n-\t\t}\n-\t\tif i < l {\n-\t\t\turi.WriteByte(r.Path[i])\n \t\t}\n-\t}\n+\t})\n \treturn uri.String()\n }", "anchor_file": "route.go", "intent": "fix(router): share route syntax across routing operations\n\n## Summary\n\nFollow-up to #3113. Three route-syntax bugs remained after it: a literal `\\:` after a parameter was swallowed into the parameter name, `Remove` could not find escaped-colon routes, and reverse routing dropped the literal verb.\n\n- **One route-syntax scanner** for registration, removal and reverse routing. An escaped colon after a parameter starts an inline verb (`/:name\\:cancel`) when the rest of that path segment is static. Other escaped colons after a parameter keep their older meaning as part of the parameter name.\n- **Inline verb matching.** At a param node with an inline verb child, the value first ends at a literal colon where the verb can match. If that route fails (path or method), the same param node is retried with the next split and finally the whole segment before routing backtracks to its parent. Static > param > any priority, group middleware and catch-all routes are unaffected by a failed split. A failed wildcard below a split keeps backtracking, so other routes below the split and then the next split are still tried.\n- **Linear time.** Split candidates are scanned once per segment, so a request with many colons costs O(path length × longest registered verb). A 1 MB path of colons routes in about 15 ms.\n- **Leaf params keep working.** When the inline verb child is a param node's only child, a value without a split still takes the rest of the path, so `GET /files/:path` next to `POST /files/:name\\:upload` still matches `/files/a/b`.\n- **Remove** finds the route by tree path and checks that the path is the one registered for that method.\n\n## Compatibility notes (release notes)\n\n- `/x/:id\\:y` now registers parameter `id` and a literal `:y`. Before, it registered one parameter named `id\\:y`\n...[truncated]"}, "repo": "labstack/echo", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "df5edd9146e40342726d71cbb71300b7fea096d0", "candidate_corpus": {"base_commit": "df5edd9146e40342726d71cbb71300b7fea096d0", "type": "repo_at_base_commit"}, "gold": {"files": ["group.go"], "given_files": ["echo.go"]}, "id": "1bcd1380aad77b043e7bba1f", "metadata": {"changed_files": ["echo.go", "group.go"], "created_at": "2026-09-16T09:06:52Z", "fix_commit": "9ce228d5b232644c40d03d40cc3e0c2df0b764a1", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 2, "deletions": 0, "is_test": false, "path": "group.go", "signals": ["same_component", "anchor_diff_mentions_gold_module", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_stem_hint"], "nonfatal_hits": {"group.go": ["group"]}}, "merged_at": "2026-09-16T09:51:44Z", "pr": 3102, "ripple_relation": ["same_component", "anchor_diff_mentions_gold_module", "gold_diff_mentions_anchor_module", "shared_changed_symbol"], "source_pr": "https://github.com/labstack/echo/pull/3102"}, "query": {"anchor_diff": "@@ -754,6 +754,12 @@ func (e *Echo) Add(method, path string, handler HandlerFunc, middleware ...Middl\n }\n \n // Group creates a new router group with prefix and optional group-level middleware.\n+// The prefix is concatenated with each route path without inserting a slash.\n+// For example:\n+//\n+//\tg := e.Group(\"/v1\")\n+//\tg.GET(\"/posts\", handler) // Registers /v1/posts.\n+//\tg.GET(\"posts\", handler) // Registers /v1posts.\n func (e *Echo) Group(prefix string, m ...MiddlewareFunc) (g *Group) {\n \tg = &Group{\n \t\tprefix: prefix,", "anchor_file": "echo.go", "intent": "docs: clarify group prefix concatenation\n\n## Summary\n\nClarify how group prefixes and route paths are joined. Related to #3099.\n\n## Changes\n\n- Explain in `Echo.Group` that no slash is inserted, with examples showing `/v1/posts` and `/v1posts`.\n- Document the same rule for nested groups in `Group.Group`.\n\nThis documents the existing behavior discussed in #3101. No runtime behavior or public API signatures change.\n\n## Test\n\n- `go test -race ./...`\n- `go vet ./...`\n- `go run honnef.co/go/tools/cmd/staticcheck@latest ./...` (v0.8.1)\n- `go run golang.org/x/lint/golint@latest -set_exit_status ./...`\n- Inspected `go doc Echo.Group` and `go doc Group.Group`.\n- A local reproduction verified the registered paths and HTTP 204 responses for `/v1/posts`, `/v1posts`, and `/v1/admin/users`.\n- `git diff --check`\n\nTests and reproduction ran with Go 1.25.10 on macOS arm64. Staticcheck selected Go 1.26.8 automatically.\n\nDocumentation impact: updated the public API's GoDoc comments and usage example.\n\n## Screenshot\n\nLocal verification report showing the rendered GoDoc, actual route checks, and race test output.\n\n\"verification\"\n\ndocs: clarify group prefix concatenation"}, "repo": "labstack/echo", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "df5edd9146e40342726d71cbb71300b7fea096d0", "candidate_corpus": {"base_commit": "df5edd9146e40342726d71cbb71300b7fea096d0", "type": "repo_at_base_commit"}, "gold": {"files": ["echo.go"], "given_files": ["group.go"]}, "id": "b33289837106be836d68fd67", "metadata": {"changed_files": ["echo.go", "group.go"], "created_at": "2026-09-16T09:06:52Z", "fix_commit": "9ce228d5b232644c40d03d40cc3e0c2df0b764a1", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 6, "deletions": 0, "is_test": false, "path": "echo.go", "signals": ["same_component", "anchor_diff_mentions_gold_module", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_stem_hint"], "nonfatal_hits": {"echo.go": ["echo"]}}, "merged_at": "2026-09-16T09:51:44Z", "pr": 3102, "ripple_relation": ["same_component", "anchor_diff_mentions_gold_module", "gold_diff_mentions_anchor_module", "shared_changed_symbol"], "source_pr": "https://github.com/labstack/echo/pull/3102"}, "query": {"anchor_diff": "@@ -128,6 +128,8 @@ func (g *Group) Match(methods []string, path string, handler HandlerFunc, middle\n }\n \n // Group creates a new sub-group with prefix and optional sub-group-level middleware.\n+// The prefix is concatenated with the parent group's prefix without inserting a slash.\n+// For example, a parent prefix of \"/v1\" and a sub-group prefix of \"/admin\" form \"/v1/admin\".\n //\n // Important! Group middlewares are executed in case there was no exact route match as by default Group registers\n // `/*` NotFound routes for itself. If this kind of behavior is not needed, then create an Echo instance with the ` noAutoRegisterRoutes `", "anchor_file": "group.go", "intent": "docs: clarify group prefix concatenation\n\n## Summary\n\nClarify how group prefixes and route paths are joined. Related to #3099.\n\n## Changes\n\n- Explain in `Echo.Group` that no slash is inserted, with examples showing `/v1/posts` and `/v1posts`.\n- Document the same rule for nested groups in `Group.Group`.\n\nThis documents the existing behavior discussed in #3101. No runtime behavior or public API signatures change.\n\n## Test\n\n- `go test -race ./...`\n- `go vet ./...`\n- `go run honnef.co/go/tools/cmd/staticcheck@latest ./...` (v0.8.1)\n- `go run golang.org/x/lint/golint@latest -set_exit_status ./...`\n- Inspected `go doc Echo.Group` and `go doc Group.Group`.\n- A local reproduction verified the registered paths and HTTP 204 responses for `/v1/posts`, `/v1posts`, and `/v1/admin/users`.\n- `git diff --check`\n\nTests and reproduction ran with Go 1.25.10 on macOS arm64. Staticcheck selected Go 1.26.8 automatically.\n\nDocumentation impact: updated the public API's GoDoc comments and usage example.\n\n## Screenshot\n\nLocal verification report showing the rendered GoDoc, actual route checks, and race test output.\n\n\"verification\"\n\ndocs: clarify group prefix concatenation"}, "repo": "labstack/echo", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "90702e71a7cde342da70b1f97e8e6420c509f939", "candidate_corpus": {"base_commit": "90702e71a7cde342da70b1f97e8e6420c509f939", "type": "repo_at_base_commit"}, "gold": {"files": ["json.go", "middleware/body_limit.go", "middleware/body_limit_test.go"], "given_files": ["bind.go"]}, "id": "cd53e060801b97c7fcf1010d", "metadata": {"changed_files": ["bind.go", "json.go", "middleware/body_limit.go", "middleware/body_limit_test.go"], "created_at": "2026-09-06T12:05:03Z", "fix_commit": "b59b347c95f78066152782c21e3c315088b49c79", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 3, "deletions": 0, "is_test": false, "path": "json.go", "signals": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}, {"additions": 38, "deletions": 24, "is_test": false, "path": "middleware/body_limit.go", "signals": ["shared_changed_symbol"]}, {"additions": 196, "deletions": 8, "is_test": true, "path": "middleware/body_limit_test.go", "signals": ["gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"json.go": ["json"], "middleware/body_limit.go": ["body", "limit", "middleware"], "middleware/body_limit_test.go": ["body", "limit", "middleware"]}}, "merged_at": "2026-09-29T19:45:18Z", "pr": 3087, "ripple_relation": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol", "gold_diff_mentions_anchor_module", "optional_test_ripple"], "source_pr": "https://github.com/labstack/echo/pull/3087"}, "query": {"anchor_diff": "@@ -78,20 +78,16 @@ func BindBody(c *Context, target any) (err error) {\n \tswitch mediatype {\n \tcase MIMEApplicationJSON:\n \t\tif err = c.Echo().JSONSerializer.Deserialize(c, target); err != nil {\n-\t\t\tvar hErr *HTTPError\n-\t\t\tif errors.As(err, &hErr) {\n-\t\t\t\treturn err\n-\t\t\t}\n-\t\t\treturn ErrBadRequest.Wrap(err)\n+\t\t\treturn wrapBindBodyError(err)\n \t\t}\n \tcase MIMEApplicationXML, MIMETextXML:\n \t\tif err = xml.NewDecoder(req.Body).Decode(target); err != nil {\n-\t\t\treturn ErrBadRequest.Wrap(err)\n+\t\t\treturn wrapBindBodyError(err)\n \t\t}\n \tcase MIMEApplicationForm:\n \t\tparams, err := c.FormValues()\n \t\tif err != nil {\n-\t\t\treturn ErrBadRequest.Wrap(err)\n+\t\t\treturn wrapBindBodyError(err)\n \t\t}\n \t\tif err = bindData(target, params, \"form\", nil); err != nil {\n \t\t\treturn ErrBadRequest.Wrap(err)\n@@ -99,7 +95,7 @@ func BindBody(c *Context, target any) (err error) {\n \tcase MIMEMultipartForm:\n \t\tparams, err := c.MultipartForm()\n \t\tif err != nil {\n-\t\t\treturn ErrBadRequest.Wrap(err)\n+\t\t\treturn wrapBindBodyError(err)\n \t\t}\n \t\tif err = bindData(target, params.Value, \"form\", params.File); err != nil {\n \t\t\treturn ErrBadRequest.Wrap(err)\n@@ -110,6 +106,13 @@ func BindBody(c *Context, target any) (err error) {\n \treturn nil\n }\n \n+func wrapBindBodyError(err error) error {\n+\tif StatusCode(err) != 0 {\n+\t\treturn err\n+\t}\n+\treturn ErrBadRequest.Wrap(err)\n+}\n+\n // BindHeaders binds HTTP headers to a bindable object\n func BindHeaders(c *Context, target any) error {\n \tif err := bindData(target, c.Request().Header, \"header\", nil); err != nil {", "anchor_file": "bind.go", "intent": "fix(middleware): prevent BodyLimit bypass with contract-compliant readers\n\n## Problem\n\nWith unknown `Content-Length`, `BodyLimit` forwarded an unbounded read to the underlying body. A caller that processes the returned `n > 0` bytes could receive more than the configured limit. The v4.15.2 JSON example in #3071 also accepted an oversized body. Current v5 uses `ReadFrom` followed by `json.Unmarshal` for default JSON binding, so that particular Bind bypass does not reproduce on v5; its read error was instead reported as HTTP 400.\n\n## Changes\n\n- Cap each underlying read at `remaining + 1`, return only bytes within the limit, and make the 413 error sticky after overflow.\n- Give each request its own reader. `req.Body` remains valid for outer middleware and code that uses it after the handler returns.\n- Reject negative `LimitBytes` in `ToMiddleware`.\n- Preserve status-coded body read errors through JSON, XML, form, and multipart binding, so an oversized body returns HTTP 413.\n\nThis reader retains Echo's status-coded error contract. Unlike `http.MaxBytesReader`, it does not signal `net/http` to close the connection after overflow; that is existing BodyLimit behavior and can be evaluated separately.\n\n## Verification\n\n- Regression tests cover oversized reads, exact-size bodies, `math.MaxInt64`, source errors, reader lifetime, invalid configuration, and HTTP 413 from JSON, XML, form, and multipart binding.\n- `go test ./... -count=1` passes on the PR branch and with this patch applied to the latest tracked master commit.\n- `go vet ./...` and `go test -race ./middleware -run TestBodyLimit -count=1` pass.\n\nRefs #3071. The v4 backport is still needed before closing the issue.\n\nfix(middleware): prevent BodyLimit bypass with contract-compliant readers\n\nfix(middleware): keep source read\n...[truncated]"}, "repo": "labstack/echo", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "90702e71a7cde342da70b1f97e8e6420c509f939", "candidate_corpus": {"base_commit": "90702e71a7cde342da70b1f97e8e6420c509f939", "type": "repo_at_base_commit"}, "gold": {"files": ["bind.go", "middleware/body_limit_test.go"], "given_files": ["json.go"]}, "id": "f23caed4b3a5f63d62f01401", "metadata": {"changed_files": ["bind.go", "json.go", "middleware/body_limit.go", "middleware/body_limit_test.go"], "created_at": "2026-09-06T12:05:03Z", "fix_commit": "b59b347c95f78066152782c21e3c315088b49c79", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 11, "deletions": 8, "is_test": false, "path": "bind.go", "signals": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 196, "deletions": 8, "is_test": true, "path": "middleware/body_limit_test.go", "signals": ["gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"bind.go": ["bind"], "middleware/body_limit_test.go": ["body", "limit", "middleware"]}}, "merged_at": "2026-09-29T19:45:18Z", "pr": 3087, "ripple_relation": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/labstack/echo/pull/3087"}, "query": {"anchor_diff": "@@ -54,6 +54,9 @@ func (d DefaultJSONSerializer) Deserialize(c *Context, target any) error {\n \t\t}\n \t}()\n \tif _, err := buf.ReadFrom(c.Request().Body); err != nil {\n+\t\tif StatusCode(err) != 0 {\n+\t\t\treturn err\n+\t\t}\n \t\treturn ErrBadRequest.Wrap(err)\n \t}\n \tif err := json.Unmarshal(buf.Bytes(), target); err != nil {", "anchor_file": "json.go", "intent": "fix(middleware): prevent BodyLimit bypass with contract-compliant readers\n\n## Problem\n\nWith unknown `Content-Length`, `BodyLimit` forwarded an unbounded read to the underlying body. A caller that processes the returned `n > 0` bytes could receive more than the configured limit. The v4.15.2 JSON example in #3071 also accepted an oversized body. Current v5 uses `ReadFrom` followed by `json.Unmarshal` for default JSON binding, so that particular Bind bypass does not reproduce on v5; its read error was instead reported as HTTP 400.\n\n## Changes\n\n- Cap each underlying read at `remaining + 1`, return only bytes within the limit, and make the 413 error sticky after overflow.\n- Give each request its own reader. `req.Body` remains valid for outer middleware and code that uses it after the handler returns.\n- Reject negative `LimitBytes` in `ToMiddleware`.\n- Preserve status-coded body read errors through JSON, XML, form, and multipart binding, so an oversized body returns HTTP 413.\n\nThis reader retains Echo's status-coded error contract. Unlike `http.MaxBytesReader`, it does not signal `net/http` to close the connection after overflow; that is existing BodyLimit behavior and can be evaluated separately.\n\n## Verification\n\n- Regression tests cover oversized reads, exact-size bodies, `math.MaxInt64`, source errors, reader lifetime, invalid configuration, and HTTP 413 from JSON, XML, form, and multipart binding.\n- `go test ./... -count=1` passes on the PR branch and with this patch applied to the latest tracked master commit.\n- `go vet ./...` and `go test -race ./middleware -run TestBodyLimit -count=1` pass.\n\nRefs #3071. The v4 backport is still needed before closing the issue.\n\nfix(middleware): prevent BodyLimit bypass with contract-compliant readers\n\nfix(middleware): keep source read\n...[truncated]"}, "repo": "labstack/echo", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "ed8bbe4b6cbf519766c99e492b9cc427404b3719", "candidate_corpus": {"base_commit": "ed8bbe4b6cbf519766c99e492b9cc427404b3719", "type": "repo_at_base_commit"}, "gold": {"files": ["middleware/request_id.go"], "given_files": ["middleware/request_logger.go"]}, "id": "ea21bfd781d82bba763ad66c", "metadata": {"changed_files": ["middleware/request_id.go", "middleware/request_logger.go"], "created_at": "2026-07-22T05:44:08Z", "fix_commit": "548779a93a4722e3b9408e571a3c1762ff49906c", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 2, "deletions": 2, "is_test": false, "path": "middleware/request_id.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"middleware/request_id.go": ["middleware", "request"]}}, "merged_at": "2026-07-23T05:30:23Z", "pr": 3057, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/labstack/echo/pull/3057"}, "query": {"anchor_diff": "@@ -154,7 +154,7 @@ type RequestLoggerConfig struct {\n \tLogURIPath bool\n \t// LogRoutePath instructs logger to extract route path part to which request was matched to (i.e. `/user/:id`)\n \tLogRoutePath bool\n-\t// LogRequestID instructs logger to extract request ID from request `X-Request-ID` header or response if request did not have value.\n+\t// LogRequestID instructs logger to extract request ID from request `X-Request-Id` header or response if request did not have value.\n \tLogRequestID bool\n \t// LogReferer instructs logger to extract request referer values.\n \tLogReferer bool\n@@ -205,7 +205,7 @@ type RequestLoggerValues struct {\n \tURIPath string\n \t// RoutePath is route path part to which request was matched to (i.e. `/user/:id`)\n \tRoutePath string\n-\t// RequestID is request ID from request `X-Request-ID` header or response if request did not have value.\n+\t// RequestID is request ID from request `X-Request-Id` header or response if request did not have value.\n \tRequestID string\n \t// Referer is request referer values.\n \tReferer string", "anchor_file": "middleware/request_logger.go", "intent": "docs(middleware): align RequestID header spelling with HeaderXRequestID\n\n## Summary\nRequestID middleware godoc mixed `X-Request-ID` and `X-Request-Id`. HTTP header names are case-insensitive, but docs should match `echo.HeaderXRequestID` (`X-Request-Id`).\n\n## Test plan\n- docs only\n\ndocs(middleware): align RequestID header spelling with HeaderXRequestID"}, "repo": "labstack/echo", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "ed8bbe4b6cbf519766c99e492b9cc427404b3719", "candidate_corpus": {"base_commit": "ed8bbe4b6cbf519766c99e492b9cc427404b3719", "type": "repo_at_base_commit"}, "gold": {"files": ["middleware/request_logger.go"], "given_files": ["middleware/request_id.go"]}, "id": "f1d6ddf6ca56b250099c2384", "metadata": {"changed_files": ["middleware/request_id.go", "middleware/request_logger.go"], "created_at": "2026-07-22T05:44:08Z", "fix_commit": "548779a93a4722e3b9408e571a3c1762ff49906c", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 2, "deletions": 2, "is_test": false, "path": "middleware/request_logger.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"middleware/request_logger.go": ["middleware", "request"]}}, "merged_at": "2026-07-23T05:30:23Z", "pr": 3057, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/labstack/echo/pull/3057"}, "query": {"anchor_diff": "@@ -24,7 +24,7 @@ type RequestIDConfig struct {\n \tTargetHeader string\n }\n \n-// RequestID returns a middleware that reads RequestIDConfig.TargetHeader (`X-Request-ID`) header value or when\n+// RequestID returns a middleware that reads RequestIDConfig.TargetHeader (`X-Request-Id`) header value or when\n // the header value is empty, generates that value and sets request ID to response\n // as RequestIDConfig.TargetHeader (`X-Request-Id`) value.\n func RequestID() echo.MiddlewareFunc {\n@@ -32,7 +32,7 @@ func RequestID() echo.MiddlewareFunc {\n }\n \n // RequestIDWithConfig returns a middleware with given valid config or panics on invalid configuration.\n-// The middleware reads RequestIDConfig.TargetHeader (`X-Request-ID`) header value or when the header value is empty,\n+// The middleware reads RequestIDConfig.TargetHeader (`X-Request-Id`) header value or when the header value is empty,\n // generates that value and sets request ID to response as RequestIDConfig.TargetHeader (`X-Request-Id`) value.\n func RequestIDWithConfig(config RequestIDConfig) echo.MiddlewareFunc {\n \treturn toMiddlewareOrPanic(config)", "anchor_file": "middleware/request_id.go", "intent": "docs(middleware): align RequestID header spelling with HeaderXRequestID\n\n## Summary\nRequestID middleware godoc mixed `X-Request-ID` and `X-Request-Id`. HTTP header names are case-insensitive, but docs should match `echo.HeaderXRequestID` (`X-Request-Id`).\n\n## Test plan\n- docs only\n\ndocs(middleware): align RequestID header spelling with HeaderXRequestID"}, "repo": "labstack/echo", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "ed8bbe4b6cbf519766c99e492b9cc427404b3719", "candidate_corpus": {"base_commit": "ed8bbe4b6cbf519766c99e492b9cc427404b3719", "type": "repo_at_base_commit"}, "gold": {"files": ["context.go", "context_test.go"], "given_files": ["ip.go"]}, "id": "8209c3211ca9d776796f4866", "metadata": {"changed_files": ["context.go", "context_test.go", "ip.go"], "created_at": "2026-07-22T05:41:30Z", "fix_commit": "a45f07d7e4e0655424f56bc9964f395c7d6dc0ec", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 2, "deletions": 3, "is_test": false, "path": "context.go", "signals": ["same_component", "shared_changed_symbol"]}, {"additions": 12, "deletions": 0, "is_test": true, "path": "context_test.go", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"context.go": ["context"], "context_test.go": ["context"]}}, "merged_at": "2026-07-23T05:27:31Z", "pr": 3054, "ripple_relation": ["same_component", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/labstack/echo/pull/3054"}, "query": {"anchor_diff": "@@ -304,6 +304,5 @@ func legacyIPExtractor(req *http.Request) string {\n \t\tip = strings.TrimSuffix(ip, \"]\")\n \t\treturn ip\n \t}\n-\tra, _, _ := net.SplitHostPort(req.RemoteAddr)\n-\treturn ra\n+\treturn extractIP(req)\n }", "anchor_file": "ip.go", "intent": "fix: resolve RealIP for bare RemoteAddr without port\n\n## Summary\n`Context.RealIP()` (and the `LegacyIPExtractor` fallback) used `net.SplitHostPort` and ignored the error, so a bare IP `RemoteAddr` (no `:port`) returned an empty string.\n\n## Change\n- Fall back through `extractIP`, the same helper used by `ExtractIPDirect`.\n- Add unit tests for bare IPv4 and IPv6 `RemoteAddr` values.\n\n## Test plan\n- [x] `go test . -run TestContext_RealIP`\n\nfix: resolve RealIP for bare RemoteAddr without port"}, "repo": "labstack/echo", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "ed8bbe4b6cbf519766c99e492b9cc427404b3719", "candidate_corpus": {"base_commit": "ed8bbe4b6cbf519766c99e492b9cc427404b3719", "type": "repo_at_base_commit"}, "gold": {"files": ["ip.go", "context_test.go"], "given_files": ["context.go"]}, "id": "f3af919cd1860907725ef166", "metadata": {"changed_files": ["context.go", "context_test.go", "ip.go"], "created_at": "2026-07-22T05:41:30Z", "fix_commit": "a45f07d7e4e0655424f56bc9964f395c7d6dc0ec", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 1, "deletions": 2, "is_test": false, "path": "ip.go", "signals": ["same_component", "shared_changed_symbol"]}, {"additions": 12, "deletions": 0, "is_test": true, "path": "context_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"context_test.go": ["context"]}}, "merged_at": "2026-07-23T05:27:31Z", "pr": 3054, "ripple_relation": ["same_component", "shared_changed_symbol", "path_token_overlap", "gold_diff_mentions_anchor_module", "optional_test_ripple"], "source_pr": "https://github.com/labstack/echo/pull/3054"}, "query": {"anchor_diff": "@@ -12,7 +12,6 @@ import (\n \t\"io/fs\"\n \t\"log/slog\"\n \t\"mime/multipart\"\n-\t\"net\"\n \t\"net/http\"\n \t\"net/url\"\n \t\"path\"\n@@ -252,8 +251,8 @@ func (c *Context) RealIP() string {\n \t}\n \t// req.RemoteAddr is the IP address of the remote end of the connection, which may be a proxy. It is populated by the\n \t// http.conn.readRequest() method and uses net.Conn.RemoteAddr().String() which we trust.\n-\tra, _, _ := net.SplitHostPort(c.request.RemoteAddr)\n-\treturn ra\n+\t// Use extractIP so bare IPs (no host:port) still resolve, matching ExtractIPDirect.\n+\treturn extractIP(c.request)\n }\n \n // Path returns the registered path for the handler.", "anchor_file": "context.go", "intent": "fix: resolve RealIP for bare RemoteAddr without port\n\n## Summary\n`Context.RealIP()` (and the `LegacyIPExtractor` fallback) used `net.SplitHostPort` and ignored the error, so a bare IP `RemoteAddr` (no `:port`) returned an empty string.\n\n## Change\n- Fall back through `extractIP`, the same helper used by `ExtractIPDirect`.\n- Add unit tests for bare IPv4 and IPv6 `RemoteAddr` values.\n\n## Test plan\n- [x] `go test . -run TestContext_RealIP`\n\nfix: resolve RealIP for bare RemoteAddr without port"}, "repo": "labstack/echo", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "11aa3714cd0e6e9d170974009f599a58171cdc94", "candidate_corpus": {"base_commit": "11aa3714cd0e6e9d170974009f599a58171cdc94", "type": "repo_at_base_commit"}, "gold": {"files": ["echo.go", "bind.go", "group.go", "router_test.go"], "given_files": ["router.go"]}, "id": "818edf001f3db25b96b74dc7", "metadata": {"changed_files": ["bind.go", "bind_test.go", "echo.go", "echo_test.go", "group.go", "group_test.go", "router.go", "router_test.go"], "created_at": "2026-07-08T06:15:58Z", "fix_commit": "abbb92edbb1fdeeee5fb354e875320b3b131dfd5", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 9, "deletions": 0, "is_test": false, "path": "echo.go", "signals": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 2, "deletions": 2, "is_test": false, "path": "bind.go", "signals": ["same_component", "shared_changed_symbol"]}, {"additions": 5, "deletions": 0, "is_test": false, "path": "group.go", "signals": ["same_component", "shared_changed_symbol"]}, {"additions": 1, "deletions": 0, "is_test": true, "path": "router_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"bind.go": ["bind"], "echo.go": ["echo"], "group.go": ["group"], "router_test.go": ["router"]}}, "merged_at": "2026-07-08T07:32:24Z", "pr": 3038, "ripple_relation": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "path_token_overlap", "optional_test_ripple"], "source_pr": "https://github.com/labstack/echo/pull/3038"}, "query": {"anchor_diff": "@@ -161,6 +161,7 @@ type routeMethods struct {\n \tput *routeMethod\n \ttrace *routeMethod\n \treport *routeMethod\n+\tquery *routeMethod\n \tany *routeMethod\n \tanyOther map[string]*routeMethod\n \n@@ -196,6 +197,8 @@ func (m *routeMethods) set(method string, r *routeMethod) {\n \t\tm.trace = r\n \tcase REPORT:\n \t\tm.report = r\n+\tcase QUERY:\n+\t\tm.query = r\n \tcase RouteAny:\n \t\tm.any = r\n \tcase RouteNotFound:\n@@ -239,6 +242,8 @@ func (m *routeMethods) find(method string, fallbackToAny bool) *routeMethod {\n \t\tr = m.trace\n \tcase REPORT:\n \t\tr = m.report\n+\tcase QUERY:\n+\t\tr = m.query\n \tcase RouteAny:\n \t\tr = m.any\n \tcase RouteNotFound:\n@@ -295,6 +300,9 @@ func (m *routeMethods) updateAllowHeader() {\n \tif hasAnyMethod || m.report != nil {\n \t\tbuf.WriteString(\", REPORT\")\n \t}\n+\tif hasAnyMethod || m.query != nil {\n+\t\tbuf.WriteString(\", QUERY\")\n+\t}\n \tfor method := range m.anyOther { // for simplicity, we use map and therefore order is not deterministic here\n \t\tbuf.WriteString(\", \")\n \t\tbuf.WriteString(method)\n@@ -314,6 +322,7 @@ func (m *routeMethods) isHandler() bool {\n \t\tm.propfind != nil ||\n \t\tm.trace != nil ||\n \t\tm.report != nil ||\n+\t\tm.query != nil ||\n \t\tm.any != nil ||\n \t\tlen(m.anyOther) != 0\n \t// RouteNotFound/404 is not considered as a handler", "anchor_file": "router.go", "intent": "feat: add support for HTTP QUERY method\n\nCloses #3036\n\nAdds first-class support for the [QUERY HTTP method (RFC 10008)](https://www.rfc-editor.org/info/rfc10008/), so it can be registered with dedicated helpers rather than only through the generic `Add(\"QUERY\", ...)`.\n\nSince `QUERY` is not (yet) part of the `net/http` standard library, it is defined and wired in exactly the way the existing non-standard `PROPFIND` and `REPORT` methods are handled:\n\n- Add the `QUERY` method constant.\n- Add `Echo.QUERY` and `Group.QUERY` route helpers (the `Group` helper was the specific ask in the issue).\n- Give `QUERY` a dedicated field in `routeMethods` and wire it into `set`, `find`, `updateAllowHeader`, and `isHandler`.\n- Bind URL query parameters for `QUERY` (alongside GET/DELETE/HEAD) in the default binder — `QUERY` is semantically a GET carrying its query in the body, matching the gotcha @aldas flagged in the issue.\n\nfeat: add support for HTTP QUERY method (#3036)"}, "repo": "labstack/echo", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "11aa3714cd0e6e9d170974009f599a58171cdc94", "candidate_corpus": {"base_commit": "11aa3714cd0e6e9d170974009f599a58171cdc94", "type": "repo_at_base_commit"}, "gold": {"files": ["group.go", "router.go", "bind.go", "echo_test.go"], "given_files": ["echo.go"]}, "id": "a7331588605883ac0d9971e7", "metadata": {"changed_files": ["bind.go", "bind_test.go", "echo.go", "echo_test.go", "group.go", "group_test.go", "router.go", "router_test.go"], "created_at": "2026-07-08T06:15:58Z", "fix_commit": "abbb92edbb1fdeeee5fb354e875320b3b131dfd5", "generated_at": "2026-10-17T09:00:51+00:00", "gold_evidence": [{"additions": 5, "deletions": 0, "is_test": false, "path": "group.go", "signals": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 9, "deletions": 0, "is_test": false, "path": "router.go", "signals": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}, {"additions": 2, "deletions": 2, "is_test": false, "path": "bind.go", "signals": ["same_component", "shared_changed_symbol"]}, {"additions": 17, "deletions": 0, "is_test": true, "path": "echo_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"bind.go": ["bind"], "echo_test.go": ["echo"], "group.go": ["group"], "router.go": ["router"]}}, "merged_at": "2026-07-08T07:32:24Z", "pr": 3038, "ripple_relation": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "anchor_diff_mentions_gold_module", "path_token_overlap", "optional_test_ripple"], "source_pr": "https://github.com/labstack/echo/pull/3038"}, "query": {"anchor_diff": "@@ -170,6 +170,9 @@ const (\n \tPROPFIND = \"PROPFIND\"\n \t// REPORT Method can be used to get information about a resource, see rfc 3253\n \tREPORT = \"REPORT\"\n+\t// QUERY Method is a safe, idempotent request method carrying request content (a query) in its body, see rfc 10008.\n+\t// It is not (yet) part of the `net/http` standard library, so Echo defines it here.\n+\tQUERY = \"QUERY\"\n \t// RouteNotFound is special method type for routes handling \"route not found\" (404) cases\n \tRouteNotFound = \"echo_route_not_found\"\n \t// RouteAny is special method type that matches any HTTP method in request. Any has lower\n@@ -539,6 +542,12 @@ func (e *Echo) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo {\n \treturn e.Add(http.MethodPut, path, h, m...)\n }\n \n+// QUERY registers a new QUERY route for a path with matching handler in the\n+// router with optional route-level middleware. Panics on error.\n+func (e *Echo) QUERY(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo {\n+\treturn e.Add(QUERY, path, h, m...)\n+}\n+\n // TRACE registers a new TRACE route for a path with matching handler in the\n // router with optional route-level middleware. Panics on error.\n func (e *Echo) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) RouteInfo {", "anchor_file": "echo.go", "intent": "feat: add support for HTTP QUERY method\n\nCloses #3036\n\nAdds first-class support for the [QUERY HTTP method (RFC 10008)](https://www.rfc-editor.org/info/rfc10008/), so it can be registered with dedicated helpers rather than only through the generic `Add(\"QUERY\", ...)`.\n\nSince `QUERY` is not (yet) part of the `net/http` standard library, it is defined and wired in exactly the way the existing non-standard `PROPFIND` and `REPORT` methods are handled:\n\n- Add the `QUERY` method constant.\n- Add `Echo.QUERY` and `Group.QUERY` route helpers (the `Group` helper was the specific ask in the issue).\n- Give `QUERY` a dedicated field in `routeMethods` and wire it into `set`, `find`, `updateAllowHeader`, and `isHandler`.\n- Bind URL query parameters for `QUERY` (alongside GET/DELETE/HEAD) in the default binder — `QUERY` is semantically a GET carrying its query in the body, matching the gotcha @aldas flagged in the issue.\n\nfeat: add support for HTTP QUERY method (#3036)"}, "repo": "labstack/echo", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "f2878bab8c96afd6e36968af96343b35dbb82a82", "candidate_corpus": {"base_commit": "f2878bab8c96afd6e36968af96343b35dbb82a82", "type": "repo_at_base_commit"}, "gold": {"files": ["args_test.go"], "given_files": ["args.go"]}, "id": "a370cb105e09c889a5c39c5e", "metadata": {"changed_files": ["args.go", "args_test.go", "site/content/user_guide.md"], "created_at": "2026-04-24T14:41:20Z", "fix_commit": "ad460ea8f249db69c943a365fb84f3a59042d54e", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 37, "deletions": 0, "is_test": true, "path": "args_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"args_test.go": ["args"]}}, "merged_at": "2026-04-25T23:07:42Z", "pr": 2397, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/spf13/cobra/pull/2397"}, "query": {"anchor_diff": "@@ -65,6 +65,19 @@ func OnlyValidArgs(cmd *Command, args []string) error {\n \treturn nil\n }\n \n+// NoDuplicateArgs returns an error if there are any duplicate positional args.\n+func NoDuplicateArgs(cmd *Command, args []string) error {\n+\tseen := make(map[string]struct{}, len(args))\n+\tfor _, arg := range args {\n+\t\tif _, ok := seen[arg]; ok {\n+\t\t\treturn fmt.Errorf(\"duplicate argument %q for %q\", arg, cmd.CommandPath())\n+\t\t}\n+\t\tseen[arg] = struct{}{}\n+\t}\n+\n+\treturn nil\n+}\n+\n // ArbitraryArgs never returns an error.\n func ArbitraryArgs(cmd *Command, args []string) error {\n \treturn nil", "anchor_file": "args.go", "intent": "#2396: Add cobra unique args validator\n\n#2396: Add cobra unique args validator `NoDuplicateArgs`\n\n#2396: Add cobra unique args validator"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "61968e893eee2f27696c2fbc8e34fa5c4afaf7c4", "candidate_corpus": {"base_commit": "61968e893eee2f27696c2fbc8e34fa5c4afaf7c4", "type": "repo_at_base_commit"}, "gold": {"files": ["completions_test.go"], "given_files": ["completions.go"]}, "id": "8676246e904816ae2ded5b08", "metadata": {"changed_files": ["completions.go", "completions_test.go"], "created_at": "2026-02-10T08:14:44Z", "fix_commit": "746ef07158728502482cea9f880a6f4b21ef29a9", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 55, "deletions": 0, "is_test": true, "path": "completions_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"completions_test.go": ["completions"]}}, "merged_at": "2026-04-24T20:41:58Z", "pr": 2356, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/spf13/cobra/pull/2356"}, "query": {"anchor_diff": "@@ -317,7 +317,10 @@ func (c *Command) getCompletions(args []string) (*Command, []Completion, ShellCo\n \t// The last argument, which is not completely typed by the user,\n \t// should not be part of the list of arguments\n \ttoComplete := args[len(args)-1]\n-\ttrimmedArgs := args[:len(args)-1]\n+\t// Copy trimmedArgs to a new slice to avoid mutating the caller's\n+\t// backing array (which may be os.Args) when later appending \"--\".\n+\ttrimmedArgs := make([]string, len(args)-1)\n+\tcopy(trimmedArgs, args[:len(args)-1])\n \n \tvar finalCmd *Command\n \tvar finalArgs []string", "anchor_file": "completions.go", "intent": "fix: prevent completions from mutating os.Args via append side effect\n\n## Summary\n\n- Fixes a bug where `getCompletions()` accidentally mutates `os.Args` by writing `\"--\"` into the shared backing array via an `append` with spare capacity\n- Uses a three-index slice expression (`finalArgs[:len:len]`) to cap the slice capacity, forcing `append` to allocate a new array\n- Adds a regression test that confirms the args slice is not corrupted during shell completion\n\n## Details\n\nWhen shell completions are requested (e.g., `prog __complete x`), `getCompletions()` calls:\n\n```go\n_ = finalCmd.ParseFlags(append(finalArgs, \"--\"))\n```\n\n`finalArgs` is a sub-slice of the original args (derived from `os.Args[1:]`), and if it has spare capacity in its backing array, `append` writes `\"--\"` directly into the shared memory rather than allocating a new slice. This corrupts `os.Args`, which users may be inspecting in their `ValidArgsFunction`.\n\nThe fix uses `finalArgs[:len(finalArgs):len(finalArgs)]` to limit the capacity to the length, guaranteeing that `append` allocates a fresh backing array.\n\nThe bug is most visible with `TraverseChildren: true`, since `Traverse()` returns sub-slices that preserve the original backing array's capacity.\n\nFixes #2257\n\n## Test plan\n\n- [x] Added `TestCompletionDoesNotMutateArgs` that fails without the fix and passes with it\n- [x] Full test suite passes (`go test ./...`)\n\nfix: prevent completions from mutating os.Args via append side effect\n\ntest: check os.Args directly in completion mutation test\n\naddress review: copy trimmedArgs upfront, rename prog to root"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "f98cf4216d3cb5235e6e0cd00ee00959deb1dc65", "candidate_corpus": {"base_commit": "f98cf4216d3cb5235e6e0cd00ee00959deb1dc65", "type": "repo_at_base_commit"}, "gold": {"files": ["command_test.go"], "given_files": ["command.go"]}, "id": "e93bd08de47ddaaa1ef53480", "metadata": {"changed_files": ["command.go", "command_test.go"], "created_at": "2025-02-20T15:05:06Z", "fix_commit": "1995054b003053cc1e404bccfbf6d168e8731509", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 31, "deletions": 0, "is_test": true, "path": "command_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"command_test.go": ["command"]}}, "merged_at": "2025-02-21T12:46:15Z", "pr": 2241, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/spf13/cobra/pull/2241"}, "query": {"anchor_diff": "@@ -1296,6 +1296,11 @@ Simply type ` + c.DisplayName() + ` help [path to command] for full details.`,\n \t\t\t\t\tc.Printf(\"Unknown help topic %#q\\n\", args)\n \t\t\t\t\tCheckErr(c.Root().Usage())\n \t\t\t\t} else {\n+\t\t\t\t\t// FLow the context down to be used in help text\n+\t\t\t\t\tif cmd.ctx == nil {\n+\t\t\t\t\t\tcmd.ctx = c.ctx\n+\t\t\t\t\t}\n+\n \t\t\t\t\tcmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown\n \t\t\t\t\tcmd.InitDefaultVersionFlag() // make possible 'version' flag to be shown\n \t\t\t\t\tCheckErr(cmd.Help())", "anchor_file": "command.go", "intent": "Flow context to command in SetHelpFunc\n\nFixes https://github.com/spf13/cobra/issues/2240\n\nFlow context to command in SetHelpFunc\n\nCheck specific context\n\nlint\n\nfeedback"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "f98cf4216d3cb5235e6e0cd00ee00959deb1dc65", "candidate_corpus": {"base_commit": "f98cf4216d3cb5235e6e0cd00ee00959deb1dc65", "type": "repo_at_base_commit"}, "gold": {"files": ["completions_test.go"], "given_files": ["completions.go"]}, "id": "cf1cb1ff50465db35e275045", "metadata": {"changed_files": ["completions.go", "completions_test.go", "site/content/completions/_index.md"], "created_at": "2025-02-18T11:52:34Z", "fix_commit": "6dec1ae26659a130bdb4c985768d1853b0e1bc06", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 57, "deletions": 0, "is_test": true, "path": "completions_test.go", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"completions_test.go": ["completions"]}}, "merged_at": "2025-05-31T12:36:04Z", "pr": 2238, "ripple_relation": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/spf13/cobra/pull/2238"}, "query": {"anchor_diff": "@@ -115,6 +115,13 @@ type CompletionOptions struct {\n \tDisableDescriptions bool\n \t// HiddenDefaultCmd makes the default 'completion' command hidden\n \tHiddenDefaultCmd bool\n+\t// DefaultShellCompDirective sets the ShellCompDirective that is returned\n+\t// if no special directive can be determined\n+\tDefaultShellCompDirective *ShellCompDirective\n+}\n+\n+func (receiver *CompletionOptions) SetDefaultShellCompDirective(directive ShellCompDirective) {\n+\treceiver.DefaultShellCompDirective = &directive\n }\n \n // Completion is a string that can be used for completions\n@@ -480,6 +487,14 @@ func (c *Command) getCompletions(args []string) (*Command, []Completion, ShellCo\n \t\t}\n \t} else {\n \t\tdirective = ShellCompDirectiveDefault\n+\t\t// check current and parent commands for a custom DefaultShellCompDirective\n+\t\tfor cmd := finalCmd; cmd != nil; cmd = cmd.parent {\n+\t\t\tif cmd.CompletionOptions.DefaultShellCompDirective != nil {\n+\t\t\t\tdirective = *cmd.CompletionOptions.DefaultShellCompDirective\n+\t\t\t\tbreak\n+\t\t\t}\n+\t\t}\n+\n \t\tif flag == nil {\n \t\t\tfoundLocalNonPersistentFlag := false\n \t\t\t// If TraverseChildren is true on the root command we don't check for", "anchor_file": "completions.go", "intent": "The default ShellCompDirective can be customized for a command and its subcommands\n\nCloses #2209, #2221 \n\n#2221 proposed a solution where the custom `DefaultShellCompDirective` only applied to a given command.\n\nIn https://github.com/spf13/cobra/pull/2221#discussion_r1923845125, alternative approaches were discussed.\nWe agreed on a recursive solution, where a change applies to a command and its subcommands.\n\nTo ease review, I open a new PR for this approach.\n\nThe default ShellCompDirective can be customized.\n\nImprove documentation of DefaultShellCompDirective"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "a97f9fd47b290016526c8af2dac0531fea5cd773", "candidate_corpus": {"base_commit": "a97f9fd47b290016526c8af2dac0531fea5cd773", "type": "repo_at_base_commit"}, "gold": {"files": ["command_test.go"], "given_files": ["command.go"]}, "id": "dc0363f42cc01be6589d561d", "metadata": {"changed_files": ["command.go", "command_go120.go", "command_go121.go", "command_test.go"], "created_at": "2025-02-16T21:50:39Z", "fix_commit": "40b5bc1437a564fc795d388b23835e84f54cd1d1", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 0, "deletions": 13, "is_test": true, "path": "command_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"command_test.go": ["command"]}}, "merged_at": "2025-02-16T23:42:04Z", "pr": 2235, "ripple_relation": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/spf13/cobra/pull/2235"}, "query": {"anchor_diff": "@@ -23,6 +23,7 @@ import (\n \t\"fmt\"\n \t\"io\"\n \t\"os\"\n+\t\"path/filepath\"\n \t\"sort\"\n \t\"strings\"\n \n@@ -1100,11 +1101,8 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {\n \n \targs := c.args\n \n-\t// If running unit tests, we don't want to take the os.Args, see #155 and #2173.\n-\t// For example, the following would fail:\n-\t// go test -c -o foo.test\n-\t// ./foo.test -test.run TestNoArgs\n-\tif c.args == nil && !isTesting() {\n+\t// Workaround FAIL with \"go test -v\" or \"cobra.test -test.v\", see #155\n+\tif c.args == nil && filepath.Base(os.Args[0]) != \"cobra.test\" {\n \t\targs = os.Args[1:]\n \t}", "anchor_file": "command.go", "intent": "Revert \"Make detection for test-binary more universal (#2173)\"\n\nThis reverts commit d1e9d85fcf592461f3bc2f4b6d5e140c4c0aabf8.\n\nSome programs set os.Args in their unit tests and this change would break those tests.\n\nRef: https://github.com/spf13/cobra/pull/2173#issuecomment-2661544195\n\nRevert \"Make detection for test-binary more universal (#2173)\""}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "17b6dca2ffaf6113cbd1cf433ec988fa7d63c6f3", "candidate_corpus": {"base_commit": "17b6dca2ffaf6113cbd1cf433ec988fa7d63c6f3", "type": "repo_at_base_commit"}, "gold": {"files": ["completions.go", "active_help.go", "completions_test.go"], "given_files": ["command.go"]}, "id": "7dbf37397b1978da63669eeb", "metadata": {"changed_files": ["active_help.go", "command.go", "completions.go", "completions_test.go", "site/content/active_help.md", "site/content/completions/_index.md"], "created_at": "2025-02-08T01:05:12Z", "fix_commit": "8cb30f9ca53a004a6fe88c5cfcc79ac7b24fc638", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 37, "deletions": 21, "is_test": false, "path": "completions.go", "signals": ["same_component", "anchor_diff_mentions_gold_module", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 1, "deletions": 1, "is_test": false, "path": "active_help.go", "signals": ["same_component", "shared_changed_symbol"]}, {"additions": 50, "deletions": 0, "is_test": true, "path": "completions_test.go", "signals": ["gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"active_help.go": ["help"], "completions.go": ["completions"], "completions_test.go": ["completions"]}}, "merged_at": "2025-02-09T16:06:07Z", "pr": 2231, "ripple_relation": ["same_component", "anchor_diff_mentions_gold_module", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/spf13/cobra/pull/2231"}, "query": {"anchor_diff": "@@ -82,7 +82,7 @@ type Command struct {\n \tExample string\n \n \t// ValidArgs is list of all valid non-flag arguments that are accepted in shell completions\n-\tValidArgs []string\n+\tValidArgs []Completion\n \t// ValidArgsFunction is an optional function that provides valid non-flag arguments for shell completion.\n \t// It is a dynamic version of using ValidArgs.\n \t// Only one of ValidArgs and ValidArgsFunction can be used for a command.\n@@ -1272,8 +1272,8 @@ func (c *Command) InitDefaultHelpCmd() {\n \t\t\tShort: \"Help about any command\",\n \t\t\tLong: `Help provides help for any command in the application.\n Simply type ` + c.DisplayName() + ` help [path to command] for full details.`,\n-\t\t\tValidArgsFunction: func(c *Command, args []string, toComplete string) ([]string, ShellCompDirective) {\n-\t\t\t\tvar completions []string\n+\t\t\tValidArgsFunction: func(c *Command, args []string, toComplete string) ([]Completion, ShellCompDirective) {\n+\t\t\t\tvar completions []Completion\n \t\t\t\tcmd, _, e := c.Root().Find(args)\n \t\t\t\tif e != nil {\n \t\t\t\t\treturn nil, ShellCompDirectiveNoFileComp\n@@ -1285,7 +1285,7 @@ Simply type ` + c.DisplayName() + ` help [path to command] for full details.`,\n \t\t\t\tfor _, subCmd := range cmd.Commands() {\n \t\t\t\t\tif subCmd.IsAvailableCommand() || subCmd == cmd.helpCommand {\n \t\t\t\t\t\tif strings.HasPrefix(subCmd.Name(), toComplete) {\n-\t\t\t\t\t\t\tcompletions = append(completions, fmt.Sprintf(\"%s\\t%s\", subCmd.Name(), subCmd.Short))\n+\t\t\t\t\t\t\tcompletions = append(completions, CompletionWithDesc(subCmd.Name(), subCmd.Short))\n \t\t\t\t\t\t}\n \t\t\t\t\t}\n \t\t\t\t}", "anchor_file": "command.go", "intent": "feat: add CompletionWithDesc helper\n\nThe code has also been refactored to use a type alias for completion and a completion helper\n\nUsing a type alias is a non-breaking change, and it makes the code more readable and easier to understand.\n\nFixes #2222\n\nfeat: add CompletionWithDesc helper\n\nApply code review feedback\n\nchore: add unit tests for completions helper\n\nRename helpers after feedback made during the review\n\nReplace more 'string' with 'Completion'"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "17b6dca2ffaf6113cbd1cf433ec988fa7d63c6f3", "candidate_corpus": {"base_commit": "17b6dca2ffaf6113cbd1cf433ec988fa7d63c6f3", "type": "repo_at_base_commit"}, "gold": {"files": ["completions.go", "command.go", "completions_test.go"], "given_files": ["active_help.go"]}, "id": "bd1d500d0bd87f494ce47c4d", "metadata": {"changed_files": ["active_help.go", "command.go", "completions.go", "completions_test.go", "site/content/active_help.md", "site/content/completions/_index.md"], "created_at": "2025-02-08T01:05:12Z", "fix_commit": "8cb30f9ca53a004a6fe88c5cfcc79ac7b24fc638", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 37, "deletions": 21, "is_test": false, "path": "completions.go", "signals": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}, {"additions": 4, "deletions": 4, "is_test": false, "path": "command.go", "signals": ["same_component", "shared_changed_symbol"]}, {"additions": 50, "deletions": 0, "is_test": true, "path": "completions_test.go", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"completions.go": ["completions"], "completions_test.go": ["completions"]}}, "merged_at": "2025-02-09T16:06:07Z", "pr": 2231, "ripple_relation": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/spf13/cobra/pull/2231"}, "query": {"anchor_diff": "@@ -35,7 +35,7 @@ const (\n // This function can be called multiple times before and/or after completions are added to\n // the array. Each time this function is called with the same array, the new\n // ActiveHelp line will be shown below the previous ones when completion is triggered.\n-func AppendActiveHelp(compArray []string, activeHelpStr string) []string {\n+func AppendActiveHelp(compArray []Completion, activeHelpStr string) []Completion {\n \treturn append(compArray, fmt.Sprintf(\"%s%s\", activeHelpMarker, activeHelpStr))\n }", "anchor_file": "active_help.go", "intent": "feat: add CompletionWithDesc helper\n\nThe code has also been refactored to use a type alias for completion and a completion helper\n\nUsing a type alias is a non-breaking change, and it makes the code more readable and easier to understand.\n\nFixes #2222\n\nfeat: add CompletionWithDesc helper\n\nApply code review feedback\n\nchore: add unit tests for completions helper\n\nRename helpers after feedback made during the review\n\nReplace more 'string' with 'Completion'"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "01ffff4eca5a08384ef2b85f39ec0dac192a5f7b", "candidate_corpus": {"base_commit": "01ffff4eca5a08384ef2b85f39ec0dac192a5f7b", "type": "repo_at_base_commit"}, "gold": {"files": ["command.go"], "given_files": ["completions.go"]}, "id": "5303233d96a063bdec5b0998", "metadata": {"changed_files": ["command.go", "completions.go"], "created_at": "2025-01-19T23:26:18Z", "fix_commit": "6c3c1163c6df19860515103199e880122ba49e80", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "command.go", "signals": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_stem_hint"], "nonfatal_hits": {"command.go": ["command"]}}, "merged_at": "2025-01-22T01:34:05Z", "pr": 2220, "ripple_relation": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol"], "source_pr": "https://github.com/spf13/cobra/pull/2220"}, "query": {"anchor_diff": "@@ -35,7 +35,7 @@ const (\n )\n \n // Global map of flag completion functions. Make sure to use flagCompletionMutex before you try to read and write from it.\n-var flagCompletionFunctions = map[*pflag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective){}\n+var flagCompletionFunctions = map[*pflag.Flag]CompletionFunc{}\n \n // lock for reading and writing from flagCompletionFunctions\n var flagCompletionMutex = &sync.RWMutex{}\n@@ -117,22 +117,34 @@ type CompletionOptions struct {\n \tHiddenDefaultCmd bool\n }\n \n+// CompletionFunc is a function that provides completion results.\n+type CompletionFunc func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)\n+\n // NoFileCompletions can be used to disable file completion for commands that should\n // not trigger file completions.\n+//\n+// This method satisfies [CompletionFunc].\n+// It can be used with [Command.RegisterFlagCompletionFunc] and for [Command.ValidArgsFunction].\n func NoFileCompletions(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {\n \treturn nil, ShellCompDirectiveNoFileComp\n }\n \n // FixedCompletions can be used to create a completion function which always\n // returns the same results.\n-func FixedCompletions(choices []string, directive ShellCompDirective) func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {\n+//\n+// This method returns a function that satisfies [CompletionFunc]\n+// It can be used with [Command.RegisterFlagCompletionFunc] and for [Command.ValidArgsFunction].\n+func FixedCompletions(choices []string, directive ShellCompDirective) CompletionFunc {\n \treturn func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {\n \t\treturn choices, directive\n \t}\n }\n \n // RegisterFlagCompletionFunc should be called to register a function to provide completion for a flag.\n-func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)) error {\n+//\n+// You can use pre-defined completion functions such as [FixedCompletions] or [NoFileCompletions],\n+// or you can define your own.\n+func (c *Command) RegisterFlagCompletionFunc(flagName string, f CompletionFunc) error {\n \tflag := c.Flag(flagName)\n \tif flag == nil {\n \t\treturn fmt.Errorf(\"RegisterFlagCompletionFunc: flag '%s' does not exist\", flagName)\n@@ -148,7 +160,7 @@ func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Comman\n }\n \n // GetFlagCompletionFunc returns the completion function for the given flag of the command, if available.\n-func (c *Command) GetFlagCompletionFunc(flagName string) (func(*Command, []string, string) ([]string, ShellCompDirective), bool) {\n+func (c *Command) GetFlagCompletionFunc(flagName string) (CompletionFunc, bool) {\n \tflag := c.Flag(flagName)\n \tif flag == nil {\n \t\treturn nil, false\n@@ -519,7 +531,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi\n \t}\n \n \t// Find the completion function for the flag or command\n-\tvar completionFn func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)\n+\tvar completionFn CompletionFunc\n \tif flag != nil && flagCompletion {\n \t\tflagCompletionMutex.RLock()\n \t\tcompletionFn = flagCompletionFunctions[flag]", "anchor_file": "completions.go", "intent": "feat: add CompletionFunc type to help with completions\n\nAlso document that NoFilesCompletion and FixedCompletion can be used with RegisterFlagCompletionFunc.\n\nfeat: add CompletionFunc type to help with completions\n\nApply code review feedback"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "01ffff4eca5a08384ef2b85f39ec0dac192a5f7b", "candidate_corpus": {"base_commit": "01ffff4eca5a08384ef2b85f39ec0dac192a5f7b", "type": "repo_at_base_commit"}, "gold": {"files": ["completions.go"], "given_files": ["command.go"]}, "id": "e0c17940dc5bd029e37da35d", "metadata": {"changed_files": ["command.go", "completions.go"], "created_at": "2025-01-19T23:26:18Z", "fix_commit": "6c3c1163c6df19860515103199e880122ba49e80", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 17, "deletions": 5, "is_test": false, "path": "completions.go", "signals": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_stem_hint"], "nonfatal_hits": {"completions.go": ["completions"]}}, "merged_at": "2025-01-22T01:34:05Z", "pr": 2220, "ripple_relation": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol"], "source_pr": "https://github.com/spf13/cobra/pull/2220"}, "query": {"anchor_diff": "@@ -83,7 +83,7 @@ type Command struct {\n \t// ValidArgsFunction is an optional function that provides valid non-flag arguments for shell completion.\n \t// It is a dynamic version of using ValidArgs.\n \t// Only one of ValidArgs and ValidArgsFunction can be used for a command.\n-\tValidArgsFunction func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)\n+\tValidArgsFunction CompletionFunc\n \n \t// Expected arguments\n \tArgs PositionalArgs", "anchor_file": "command.go", "intent": "feat: add CompletionFunc type to help with completions\n\nAlso document that NoFilesCompletion and FixedCompletion can be used with RegisterFlagCompletionFunc.\n\nfeat: add CompletionFunc type to help with completions\n\nApply code review feedback"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "5c2c1d627d35a00153764a3d37400efc66eaca1c", "candidate_corpus": {"base_commit": "5c2c1d627d35a00153764a3d37400efc66eaca1c", "type": "repo_at_base_commit"}, "gold": {"files": ["command.go"], "given_files": ["completions.go"]}, "id": "833a7750a1442c944b6e8534", "metadata": {"changed_files": [".golangci.yml", "command.go", "completions.go"], "created_at": "2024-05-18T15:04:47Z", "fix_commit": "8003b74a10ef0d0d84fe3c408d3939d86fdeb210", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "command.go", "signals": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_stem_hint"], "nonfatal_hits": {"command.go": ["command"]}}, "merged_at": "2024-05-19T02:12:02Z", "pr": 2148, "ripple_relation": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol"], "source_pr": "https://github.com/spf13/cobra/pull/2148"}, "query": {"anchor_diff": "@@ -298,7 +298,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi\n \t}\n \tif err != nil {\n \t\t// Unable to find the real command. E.g., someInvalidCmd \n-\t\treturn c, []string{}, ShellCompDirectiveDefault, fmt.Errorf(\"Unable to find a command for arguments: %v\", trimmedArgs)\n+\t\treturn c, []string{}, ShellCompDirectiveDefault, fmt.Errorf(\"unable to find a command for arguments: %v\", trimmedArgs)\n \t}\n \tfinalCmd.ctx = c.ctx", "anchor_file": "completions.go", "intent": "Remove fully inactivated linters\n\n\"interfaces\", \"maligned\", and \"golint\" do not produce any report and cause golangci-lint to fail as we can see in the CI.\n\n- Remove \"interfaces\" and \"maligned\" linters that have no replacement.\n- Replace golint with stylecheck\n\nRemove fully inactivated linters\n\nAdd stylecheck linter, replacement for golint"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "5c2c1d627d35a00153764a3d37400efc66eaca1c", "candidate_corpus": {"base_commit": "5c2c1d627d35a00153764a3d37400efc66eaca1c", "type": "repo_at_base_commit"}, "gold": {"files": ["completions.go"], "given_files": ["command.go"]}, "id": "bd0c7369f083320061903b01", "metadata": {"changed_files": [".golangci.yml", "command.go", "completions.go"], "created_at": "2024-05-18T15:04:47Z", "fix_commit": "8003b74a10ef0d0d84fe3c408d3939d86fdeb210", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "completions.go", "signals": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": [], "nonfatal_hits": {}}, "merged_at": "2024-05-19T02:12:02Z", "pr": 2148, "ripple_relation": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol"], "source_pr": "https://github.com/spf13/cobra/pull/2148"}, "query": {"anchor_diff": "@@ -875,7 +875,7 @@ func (c *Command) ArgsLenAtDash() int {\n \n func (c *Command) execute(a []string) (err error) {\n \tif c == nil {\n-\t\treturn fmt.Errorf(\"Called Execute() on a nil Command\")\n+\t\treturn fmt.Errorf(\"called Execute() on a nil Command\")\n \t}\n \n \tif len(c.Deprecated) > 0 {", "anchor_file": "command.go", "intent": "Remove fully inactivated linters\n\n\"interfaces\", \"maligned\", and \"golint\" do not produce any report and cause golangci-lint to fail as we can see in the CI.\n\n- Remove \"interfaces\" and \"maligned\" linters that have no replacement.\n- Replace golint with stylecheck\n\nRemove fully inactivated linters\n\nAdd stylecheck linter, replacement for golint"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "bcfcff729ecdeb4072ef6f2a9c0b5e4ca1853206", "candidate_corpus": {"base_commit": "bcfcff729ecdeb4072ef6f2a9c0b5e4ca1853206", "type": "repo_at_base_commit"}, "gold": {"files": ["bash_completions.go"], "given_files": ["powershell_completions.go"]}, "id": "08046fcb5364f233a64b3833", "metadata": {"changed_files": [".golangci.yml", "bash_completions.go", "command_test.go", "doc/man_docs.go", "doc/util.go", "powershell_completions.go"], "created_at": "2024-01-15T21:47:40Z", "fix_commit": "6b5f577ebce858ee70fcdd1f062ea3af4b1c03ab", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 10, "deletions": 13, "is_test": false, "path": "bash_completions.go", "signals": ["same_component", "path_token_overlap"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": [], "nonfatal_hits": {}}, "merged_at": "2024-04-01T12:42:08Z", "pr": 2099, "ripple_relation": ["same_component", "path_token_overlap"], "source_pr": "https://github.com/spf13/cobra/pull/2099"}, "query": {"anchor_diff": "@@ -28,8 +28,8 @@ import (\n func genPowerShellComp(buf io.StringWriter, name string, includeDesc bool) {\n \t// Variables should not contain a '-' or ':' character\n \tnameForVar := name\n-\tnameForVar = strings.Replace(nameForVar, \"-\", \"_\", -1)\n-\tnameForVar = strings.Replace(nameForVar, \":\", \"_\", -1)\n+\tnameForVar = strings.ReplaceAll(nameForVar, \"-\", \"_\")\n+\tnameForVar = strings.ReplaceAll(nameForVar, \":\", \"_\")\n \n \tcompCmd := ShellCompRequestCmd\n \tif !includeDesc {", "anchor_file": "powershell_completions.go", "intent": "More linting\n\nSome old patches I've had around, refreshed.\n\nAddress gocritic findings, enable it\n\nEnable gosimple, no new findings to address"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "bcfcff729ecdeb4072ef6f2a9c0b5e4ca1853206", "candidate_corpus": {"base_commit": "bcfcff729ecdeb4072ef6f2a9c0b5e4ca1853206", "type": "repo_at_base_commit"}, "gold": {"files": ["powershell_completions.go", "doc/man_docs.go"], "given_files": ["bash_completions.go"]}, "id": "ae997b4a32d8eff3bc8ce8be", "metadata": {"changed_files": [".golangci.yml", "bash_completions.go", "command_test.go", "doc/man_docs.go", "doc/util.go", "powershell_completions.go"], "created_at": "2024-01-15T21:47:40Z", "fix_commit": "6b5f577ebce858ee70fcdd1f062ea3af4b1c03ab", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 2, "deletions": 2, "is_test": false, "path": "powershell_completions.go", "signals": ["same_component", "path_token_overlap"]}, {"additions": 1, "deletions": 1, "is_test": false, "path": "doc/man_docs.go", "signals": ["shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": [], "nonfatal_hits": {}}, "merged_at": "2024-04-01T12:42:08Z", "pr": 2099, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/spf13/cobra/pull/2099"}, "query": {"anchor_diff": "@@ -597,19 +597,16 @@ func writeRequiredFlag(buf io.StringWriter, cmd *Command) {\n \t\tif nonCompletableFlag(flag) {\n \t\t\treturn\n \t\t}\n-\t\tfor key := range flag.Annotations {\n-\t\t\tswitch key {\n-\t\t\tcase BashCompOneRequiredFlag:\n-\t\t\t\tformat := \" must_have_one_flag+=(\\\"--%s\"\n-\t\t\t\tif flag.Value.Type() != \"bool\" {\n-\t\t\t\t\tformat += \"=\"\n-\t\t\t\t}\n-\t\t\t\tformat += cbn\n-\t\t\t\tWriteStringAndCheck(buf, fmt.Sprintf(format, flag.Name))\n-\n-\t\t\t\tif len(flag.Shorthand) > 0 {\n-\t\t\t\t\tWriteStringAndCheck(buf, fmt.Sprintf(\" must_have_one_flag+=(\\\"-%s\"+cbn, flag.Shorthand))\n-\t\t\t\t}\n+\t\tif _, ok := flag.Annotations[BashCompOneRequiredFlag]; ok {\n+\t\t\tformat := \" must_have_one_flag+=(\\\"--%s\"\n+\t\t\tif flag.Value.Type() != \"bool\" {\n+\t\t\t\tformat += \"=\"\n+\t\t\t}\n+\t\t\tformat += cbn\n+\t\t\tWriteStringAndCheck(buf, fmt.Sprintf(format, flag.Name))\n+\n+\t\t\tif len(flag.Shorthand) > 0 {\n+\t\t\t\tWriteStringAndCheck(buf, fmt.Sprintf(\" must_have_one_flag+=(\\\"-%s\"+cbn, flag.Shorthand))\n \t\t\t}\n \t\t}\n \t})", "anchor_file": "bash_completions.go", "intent": "More linting\n\nSome old patches I've had around, refreshed.\n\nAddress gocritic findings, enable it\n\nEnable gosimple, no new findings to address"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "0e3a0bfe91a52670ba78ec020f3657d48954a4f7", "candidate_corpus": {"base_commit": "0e3a0bfe91a52670ba78ec020f3657d48954a4f7", "type": "repo_at_base_commit"}, "gold": {"files": ["bash_completions.go", "cobra.go"], "given_files": ["bash_completionsV2.go"]}, "id": "468362deb0a9e590e676a55b", "metadata": {"changed_files": ["bash_completions.go", "bash_completionsV2.go", "cobra.go"], "created_at": "2023-06-13T09:38:22Z", "fix_commit": "2246fa82e91dda4486b9466fab691b41b516f747", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "bash_completions.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 1, "deletions": 1, "is_test": false, "path": "cobra.go", "signals": ["same_component", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"bash_completions.go": ["bash", "completions"]}}, "merged_at": "2023-06-13T15:12:49Z", "pr": 1978, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/spf13/cobra/pull/1978"}, "query": {"anchor_diff": "@@ -57,7 +57,7 @@ __%[1]s_get_completion_results() {\n local requestComp lastParam lastChar args\n \n # Prepare the command to request completions for the program.\n- # Calling ${words[0]} instead of directly %[1]s allows to handle aliases\n+ # Calling ${words[0]} instead of directly %[1]s allows handling aliases\n args=(\"${words[@]:1}\")\n requestComp=\"${words[0]} %[2]s ${args[*]}\"", "anchor_file": "bash_completionsV2.go", "intent": "Fix grammar: 'allows to'\n\nThe use in generated bash completion files is getting flagged by Lintian (the Debian package linting tool).\n\nFix grammar: 'allows to'"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "0e3a0bfe91a52670ba78ec020f3657d48954a4f7", "candidate_corpus": {"base_commit": "0e3a0bfe91a52670ba78ec020f3657d48954a4f7", "type": "repo_at_base_commit"}, "gold": {"files": ["bash_completionsV2.go", "cobra.go"], "given_files": ["bash_completions.go"]}, "id": "b81ae83f1ba7414e34fc5bb4", "metadata": {"changed_files": ["bash_completions.go", "bash_completionsV2.go", "cobra.go"], "created_at": "2023-06-13T09:38:22Z", "fix_commit": "2246fa82e91dda4486b9466fab691b41b516f747", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "bash_completionsV2.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 1, "deletions": 1, "is_test": false, "path": "cobra.go", "signals": ["same_component", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"bash_completionsV2.go": ["bash", "completions"]}}, "merged_at": "2023-06-13T15:12:49Z", "pr": 1978, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol"], "source_pr": "https://github.com/spf13/cobra/pull/1978"}, "query": {"anchor_diff": "@@ -85,7 +85,7 @@ __%[1]s_handle_go_custom_completion()\n local out requestComp lastParam lastChar comp directive args\n \n # Prepare the command to request completions for the program.\n- # Calling ${words[0]} instead of directly %[1]s allows to handle aliases\n+ # Calling ${words[0]} instead of directly %[1]s allows handling aliases\n args=(\"${words[@]:1}\")\n # Disable ActiveHelp which is not supported for bash completion v1\n requestComp=\"%[8]s=0 ${words[0]} %[2]s ${args[*]}\"", "anchor_file": "bash_completions.go", "intent": "Fix grammar: 'allows to'\n\nThe use in generated bash completion files is getting flagged by Lintian (the Debian package linting tool).\n\nFix grammar: 'allows to'"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "bd4d1655f6655f690f45d281fe698dacb9c7d750", "candidate_corpus": {"base_commit": "bd4d1655f6655f690f45d281fe698dacb9c7d750", "type": "repo_at_base_commit"}, "gold": {"files": ["bash_completions.go", "args.go", "command.go", "cobra.go"], "given_files": ["completions.go"]}, "id": "0a2ab9b7dc488914474266ea", "metadata": {"changed_files": ["args.go", "bash_completions.go", "cobra.go", "command.go", "completions.go", "flag_groups.go"], "created_at": "2023-05-09T21:10:36Z", "fix_commit": "3d8ac432bdad89db04ab0890754b2444d7b4e1cf", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 1, "deletions": 1, "is_test": false, "path": "bash_completions.go", "signals": ["same_component", "path_token_overlap", "shared_changed_symbol"]}, {"additions": 2, "deletions": 2, "is_test": false, "path": "args.go", "signals": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}, {"additions": 5, "deletions": 5, "is_test": false, "path": "command.go", "signals": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}, {"additions": 0, "deletions": 2, "is_test": false, "path": "cobra.go", "signals": ["same_component"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"args.go": ["args"], "bash_completions.go": ["completions"], "command.go": ["command"]}}, "merged_at": "2023-11-23T17:24:33Z", "pr": 1957, "ripple_relation": ["same_component", "path_token_overlap", "shared_changed_symbol", "anchor_diff_mentions_gold_module"], "source_pr": "https://github.com/spf13/cobra/pull/1957"}, "query": {"anchor_diff": "@@ -217,23 +217,23 @@ func (c *Command) initCompleteCmd(args []string) {\n \t\t\t}\n \n \t\t\tnoDescriptions := (cmd.CalledAs() == ShellCompNoDescRequestCmd)\n+\t\t\tnoActiveHelp := GetActiveHelpConfig(finalCmd) == activeHelpGlobalDisable\n+\t\t\tout := finalCmd.OutOrStdout()\n \t\t\tfor _, comp := range completions {\n-\t\t\t\tif GetActiveHelpConfig(finalCmd) == activeHelpGlobalDisable {\n-\t\t\t\t\t// Remove all activeHelp entries in this case\n-\t\t\t\t\tif strings.HasPrefix(comp, activeHelpMarker) {\n-\t\t\t\t\t\tcontinue\n-\t\t\t\t\t}\n+\t\t\t\tif noActiveHelp && strings.HasPrefix(comp, activeHelpMarker) {\n+\t\t\t\t\t// Remove all activeHelp entries if it's disabled.\n+\t\t\t\t\tcontinue\n \t\t\t\t}\n \t\t\t\tif noDescriptions {\n \t\t\t\t\t// Remove any description that may be included following a tab character.\n-\t\t\t\t\tcomp = strings.Split(comp, \"\\t\")[0]\n+\t\t\t\t\tcomp = strings.SplitN(comp, \"\\t\", 2)[0]\n \t\t\t\t}\n \n \t\t\t\t// Make sure we only write the first line to the output.\n \t\t\t\t// This is needed if a description contains a linebreak.\n \t\t\t\t// Otherwise the shell scripts will interpret the other lines as new flags\n \t\t\t\t// and could therefore provide a wrong completion.\n-\t\t\t\tcomp = strings.Split(comp, \"\\n\")[0]\n+\t\t\t\tcomp = strings.SplitN(comp, \"\\n\", 2)[0]\n \n \t\t\t\t// Finally trim the completion. This is especially important to get rid\n \t\t\t\t// of a trailing tab when there are no description following it.\n@@ -242,14 +242,14 @@ func (c *Command) initCompleteCmd(args []string) {\n \t\t\t\t// although there is no description).\n \t\t\t\tcomp = strings.TrimSpace(comp)\n \n-\t\t\t\t// Print each possible completion to stdout for the completion script to consume.\n-\t\t\t\tfmt.Fprintln(finalCmd.OutOrStdout(), comp)\n+\t\t\t\t// Print each possible completion to the output for the completion script to consume.\n+\t\t\t\tfmt.Fprintln(out, comp)\n \t\t\t}\n \n \t\t\t// As the last printout, print the completion directive for the completion script to parse.\n \t\t\t// The directive integer must be that last character following a single colon (:).\n \t\t\t// The completion script expects :\n-\t\t\tfmt.Fprintf(finalCmd.OutOrStdout(), \":%d\\n\", directive)\n+\t\t\tfmt.Fprintf(out, \":%d\\n\", directive)\n \n \t\t\t// Print some helpful info to stderr for the user to understand.\n \t\t\t// Output from stderr must be ignored by the completion script.", "anchor_file": "completions.go", "intent": "Micro-optimizations\n\nNoticed while looking into something else. No benchmarks/numbers done, but even if this wouldn't yield measurable improvements, the changes don't hurt readability IMO and actually in a sense they convey the intent better.\n\nAvoid redundant string splits\n\nAvoid redundant completion output target evaluations\n\nAvoid redundant active help enablement evaluations\n\nPreallocate some slices and maps with known size\n\nAvoid some unnecessary looping\n\nUse strings.Builder to construct suggestions"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "bd4d1655f6655f690f45d281fe698dacb9c7d750", "candidate_corpus": {"base_commit": "bd4d1655f6655f690f45d281fe698dacb9c7d750", "type": "repo_at_base_commit"}, "gold": {"files": ["args.go", "bash_completions.go", "flag_groups.go", "completions.go"], "given_files": ["command.go"]}, "id": "daa9f5a312a976c87ba5ab03", "metadata": {"changed_files": ["args.go", "bash_completions.go", "cobra.go", "command.go", "completions.go", "flag_groups.go"], "created_at": "2023-05-09T21:10:36Z", "fix_commit": "3d8ac432bdad89db04ab0890754b2444d7b4e1cf", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 2, "deletions": 2, "is_test": false, "path": "args.go", "signals": ["same_component", "anchor_diff_mentions_gold_module", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 1, "deletions": 1, "is_test": false, "path": "bash_completions.go", "signals": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 5, "deletions": 5, "is_test": false, "path": "flag_groups.go", "signals": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 10, "deletions": 10, "is_test": false, "path": "completions.go", "signals": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"args.go": ["args"], "flag_groups.go": ["flag"]}}, "merged_at": "2023-11-23T17:24:33Z", "pr": 1957, "ripple_relation": ["same_component", "anchor_diff_mentions_gold_module", "gold_diff_mentions_anchor_module", "shared_changed_symbol"], "source_pr": "https://github.com/spf13/cobra/pull/1957"}, "query": {"anchor_diff": "@@ -701,7 +701,7 @@ Loop:\n \t\t\t// This is not a flag or a flag value. Check to see if it matches what we're looking for, and if so,\n \t\t\t// return the args, excluding the one at this position.\n \t\t\tif s == x {\n-\t\t\t\tret := []string{}\n+\t\t\t\tret := make([]string, 0, len(args)-1)\n \t\t\t\tret = append(ret, args[:pos]...)\n \t\t\t\tret = append(ret, args[pos+1:]...)\n \t\t\t\treturn ret\n@@ -749,14 +749,14 @@ func (c *Command) findSuggestions(arg string) string {\n \tif c.SuggestionsMinimumDistance <= 0 {\n \t\tc.SuggestionsMinimumDistance = 2\n \t}\n-\tsuggestionsString := \"\"\n+\tvar sb strings.Builder\n \tif suggestions := c.SuggestionsFor(arg); len(suggestions) > 0 {\n-\t\tsuggestionsString += \"\\n\\nDid you mean this?\\n\"\n+\t\tsb.WriteString(\"\\n\\nDid you mean this?\\n\")\n \t\tfor _, s := range suggestions {\n-\t\t\tsuggestionsString += fmt.Sprintf(\"\\t%v\\n\", s)\n+\t\t\t_, _ = fmt.Fprintf(&sb, \"\\t%v\\n\", s)\n \t\t}\n \t}\n-\treturn suggestionsString\n+\treturn sb.String()\n }\n \n func (c *Command) findNext(next string) *Command {", "anchor_file": "command.go", "intent": "Micro-optimizations\n\nNoticed while looking into something else. No benchmarks/numbers done, but even if this wouldn't yield measurable improvements, the changes don't hurt readability IMO and actually in a sense they convey the intent better.\n\nAvoid redundant string splits\n\nAvoid redundant completion output target evaluations\n\nAvoid redundant active help enablement evaluations\n\nPreallocate some slices and maps with known size\n\nAvoid some unnecessary looping\n\nUse strings.Builder to construct suggestions"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "09d5664f34e3f7571560e48ccb74c8904b671e87", "candidate_corpus": {"base_commit": "09d5664f34e3f7571560e48ccb74c8904b671e87", "type": "repo_at_base_commit"}, "gold": {"files": ["command.go", "cobra.go", "command_test.go", "cobra_test.go"], "given_files": ["completions.go"]}, "id": "1c5a65dcad0262acd56c7f8f", "metadata": {"changed_files": ["cobra.go", "cobra_test.go", "command.go", "command_test.go", "completions.go", "site/content/user_guide.md"], "created_at": "2023-05-05T11:49:51Z", "fix_commit": "611e16c322e3b0413a9ba4e489fcd98ef904e406", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 209, "deletions": 54, "is_test": false, "path": "command.go", "signals": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}, {"additions": 10, "deletions": 6, "is_test": false, "path": "cobra.go", "signals": ["same_component", "anchor_diff_mentions_gold_module"]}, {"additions": 58, "deletions": 0, "is_test": true, "path": "command_test.go", "signals": ["shared_changed_symbol", "optional_test_ripple"]}, {"additions": 77, "deletions": 0, "is_test": true, "path": "cobra_test.go", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"cobra.go": ["cobra"], "cobra_test.go": ["cobra"], "command.go": ["command"], "command_test.go": ["command"]}}, "merged_at": "2025-01-27T14:43:44Z", "pr": 1956, "ripple_relation": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol", "optional_test_ripple"], "source_pr": "https://github.com/spf13/cobra/pull/1956"}, "query": {"anchor_diff": "@@ -555,7 +555,7 @@ func helpOrVersionFlagPresent(cmd *Command) bool {\n \t\tlen(versionFlag.Annotations[FlagSetByCobraAnnotation]) > 0 && versionFlag.Changed {\n \t\treturn true\n \t}\n-\tif helpFlag := cmd.Flags().Lookup(\"help\"); helpFlag != nil &&\n+\tif helpFlag := cmd.Flags().Lookup(helpFlagName); helpFlag != nil &&\n \t\tlen(helpFlag.Annotations[FlagSetByCobraAnnotation]) > 0 && helpFlag.Changed {\n \t\treturn true\n \t}", "anchor_file": "completions.go", "intent": "Allow linker to perform deadcode elimination for program using Cobra\n\nFixes #2015 \n\nCobra, in its default configuration, will execute a template to generate help, usage and version outputs. Text/template execution calls MethodByName and MethodByName disables dead code elimination in the Go linker, therefore all programs that make use of cobra will be linked with dead code elimination disabled, even if they end up replacing the default usage, help and version formatters with a custom function and no actual text/template evaluations are ever made at runtime.\n\nDead code elimination in the linker helps reduce disk space and memory utilization of programs. For example, for the simple example program used by TestDeadcodeElimination 40% of the final executable size is dead code. For a more realistic example, 12% of the size of Delve's executable is deadcode.\n\nThis PR changes Cobra so that, in its default configuration, it does not automatically inhibit deadcode elimination by:\n\n1. changing Cobra's default behavior to emit output for usage and help using simple Go functions instead of template execution\n2. quarantining all calls to template execution into SetUsageTemplate, SetHelpTemplate and SetVersionTemplate so that the linker can statically determine if they are reachable\n\nSee https://github.com/aarzilli/whydeadcode to help find why dead-code-elimination may not work as well as it could in your project.\n\nRestructure code to let linker perform deadcode elimination step\n\naddressing review comments\n\nmake string \"help\" a constant\n\nmake string \"help\" a constant more\n\nSome minor cleanup\n\nAdd test\n\ndisable TestDeadcodeElimination on windows\n\nFix missing recursion"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "09d5664f34e3f7571560e48ccb74c8904b671e87", "candidate_corpus": {"base_commit": "09d5664f34e3f7571560e48ccb74c8904b671e87", "type": "repo_at_base_commit"}, "gold": {"files": ["command.go", "completions.go", "cobra_test.go", "command_test.go"], "given_files": ["cobra.go"]}, "id": "54d5cda827e036060df87ea6", "metadata": {"changed_files": ["cobra.go", "cobra_test.go", "command.go", "command_test.go", "completions.go", "site/content/user_guide.md"], "created_at": "2023-05-05T11:49:51Z", "fix_commit": "611e16c322e3b0413a9ba4e489fcd98ef904e406", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 209, "deletions": 54, "is_test": false, "path": "command.go", "signals": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol"]}, {"additions": 1, "deletions": 1, "is_test": false, "path": "completions.go", "signals": ["same_component", "gold_diff_mentions_anchor_module"]}, {"additions": 77, "deletions": 0, "is_test": true, "path": "cobra_test.go", "signals": ["path_token_overlap", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "optional_test_ripple"]}, {"additions": 58, "deletions": 0, "is_test": true, "path": "command_test.go", "signals": ["shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint"], "nonfatal_hits": {"cobra_test.go": ["cobra"]}}, "merged_at": "2025-01-27T14:43:44Z", "pr": 1956, "ripple_relation": ["same_component", "gold_diff_mentions_anchor_module", "shared_changed_symbol", "path_token_overlap", "optional_test_ripple"], "source_pr": "https://github.com/spf13/cobra/pull/1956"}, "query": {"anchor_diff": "@@ -176,12 +176,16 @@ func rpad(s string, padding int) string {\n \treturn fmt.Sprintf(formattedString, s)\n }\n \n-// tmpl executes the given template text on data, writing the result to w.\n-func tmpl(w io.Writer, text string, data interface{}) error {\n-\tt := template.New(\"top\")\n-\tt.Funcs(templateFuncs)\n-\ttemplate.Must(t.Parse(text))\n-\treturn t.Execute(w, data)\n+func tmpl(text string) *tmplFunc {\n+\treturn &tmplFunc{\n+\t\ttmpl: text,\n+\t\tfn: func(w io.Writer, data interface{}) error {\n+\t\t\tt := template.New(\"top\")\n+\t\t\tt.Funcs(templateFuncs)\n+\t\t\ttemplate.Must(t.Parse(text))\n+\t\t\treturn t.Execute(w, data)\n+\t\t},\n+\t}\n }\n \n // ld compares two strings and returns the levenshtein distance between them.", "anchor_file": "cobra.go", "intent": "Allow linker to perform deadcode elimination for program using Cobra\n\nFixes #2015 \n\nCobra, in its default configuration, will execute a template to generate help, usage and version outputs. Text/template execution calls MethodByName and MethodByName disables dead code elimination in the Go linker, therefore all programs that make use of cobra will be linked with dead code elimination disabled, even if they end up replacing the default usage, help and version formatters with a custom function and no actual text/template evaluations are ever made at runtime.\n\nDead code elimination in the linker helps reduce disk space and memory utilization of programs. For example, for the simple example program used by TestDeadcodeElimination 40% of the final executable size is dead code. For a more realistic example, 12% of the size of Delve's executable is deadcode.\n\nThis PR changes Cobra so that, in its default configuration, it does not automatically inhibit deadcode elimination by:\n\n1. changing Cobra's default behavior to emit output for usage and help using simple Go functions instead of template execution\n2. quarantining all calls to template execution into SetUsageTemplate, SetHelpTemplate and SetVersionTemplate so that the linker can statically determine if they are reachable\n\nSee https://github.com/aarzilli/whydeadcode to help find why dead-code-elimination may not work as well as it could in your project.\n\nRestructure code to let linker perform deadcode elimination step\n\naddressing review comments\n\nmake string \"help\" a constant\n\nmake string \"help\" a constant more\n\nSome minor cleanup\n\nAdd test\n\ndisable TestDeadcodeElimination on windows\n\nFix missing recursion"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} +{"audit": {"notes": "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only", "verdict": "pending"}, "base_commit": "17b6dca2ffaf6113cbd1cf433ec988fa7d63c6f3", "candidate_corpus": {"base_commit": "17b6dca2ffaf6113cbd1cf433ec988fa7d63c6f3", "type": "repo_at_base_commit"}, "gold": {"files": ["command.go", "completions_test.go"], "given_files": ["completions.go"]}, "id": "2b8214f2cbed8abb5cfa2814", "metadata": {"changed_files": ["command.go", "completions.go", "completions_test.go", "site/content/completions/_index.md"], "created_at": "2021-12-11T19:41:44Z", "fix_commit": "24ada7fe71e3a3a8741dd52e0a7fc3b97450535a", "generated_at": "2026-10-17T09:00:52+00:00", "gold_evidence": [{"additions": 8, "deletions": 7, "is_test": false, "path": "command.go", "signals": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol"]}, {"additions": 141, "deletions": 3, "is_test": true, "path": "completions_test.go", "signals": ["path_token_overlap", "shared_changed_symbol", "optional_test_ripple"]}], "leakage": {"fatal": [], "fatal_hits": {}, "nonfatal": ["gold_module_token_hint", "gold_stem_hint"], "nonfatal_hits": {"command.go": ["command"], "completions_test.go": ["completions"]}}, "merged_at": "2025-02-15T18:07:03Z", "pr": 1559, "ripple_relation": ["same_component", "anchor_diff_mentions_gold_module", "shared_changed_symbol", "path_token_overlap", "optional_test_ripple"], "source_pr": "https://github.com/spf13/cobra/pull/1559"}, "query": {"anchor_diff": "@@ -711,8 +711,8 @@ func checkIfFlagCompletion(finalCmd *Command, args []string, lastArg string) (*p\n // 1- the feature has been explicitly disabled by the program,\n // 2- c has no subcommands (to avoid creating one),\n // 3- c already has a 'completion' command provided by the program.\n-func (c *Command) InitDefaultCompletionCmd() {\n-\tif c.CompletionOptions.DisableDefaultCmd || !c.HasSubCommands() {\n+func (c *Command) InitDefaultCompletionCmd(args ...string) {\n+\tif c.CompletionOptions.DisableDefaultCmd {\n \t\treturn\n \t}\n \n@@ -725,6 +725,16 @@ func (c *Command) InitDefaultCompletionCmd() {\n \n \thaveNoDescFlag := !c.CompletionOptions.DisableNoDescFlag && !c.CompletionOptions.DisableDescriptions\n \n+\t// Special case to know if there are sub-commands or not.\n+\thasSubCommands := false\n+\tfor _, cmd := range c.commands {\n+\t\tif cmd.Name() != ShellCompRequestCmd && cmd.Name() != helpCommandName {\n+\t\t\t// We found a real sub-command (not 'help' or '__complete')\n+\t\t\thasSubCommands = true\n+\t\t\tbreak\n+\t\t}\n+\t}\n+\n \tcompletionCmd := &Command{\n \t\tUse: compCmdName,\n \t\tShort: \"Generate the autocompletion script for the specified shell\",\n@@ -738,6 +748,22 @@ See each sub-command's help for details on how to use the generated script.\n \t}\n \tc.AddCommand(completionCmd)\n \n+\tif !hasSubCommands {\n+\t\t// If the 'completion' command will be the only sub-command,\n+\t\t// we only create it if it is actually being called.\n+\t\t// This avoids breaking programs that would suddenly find themselves with\n+\t\t// a subcommand, which would prevent them from accepting arguments.\n+\t\t// We also create the 'completion' command if the user is triggering\n+\t\t// shell completion for it (prog __complete completion '')\n+\t\tsubCmd, cmdArgs, err := c.Find(args)\n+\t\tif err != nil || subCmd.Name() != compCmdName &&\n+\t\t\t!(subCmd.Name() == ShellCompRequestCmd && len(cmdArgs) > 1 && cmdArgs[0] == compCmdName) {\n+\t\t\t// The completion command is not being called or being completed so we remove it.\n+\t\t\tc.RemoveCommand(completionCmd)\n+\t\t\treturn\n+\t\t}\n+\t}\n+\n \tout := c.OutOrStdout()\n \tnoDesc := c.CompletionOptions.DisableDescriptions\n \tshortDesc := \"Generate the autocompletion script for %s\"", "anchor_file": "completions.go", "intent": "Add default completion command even if there are no other sub-commands\n\nThis supersedes #1450 and #1392\n\nWhen a program has no sub-commands, its root command can accept arguments. If we add the default \"completion\" command to such programs they will now have a sub-command and will no longer accept arguments.\n\nWhat we do instead for this special case, is only add the \"completion\" command if it is being called.\n\nWe want to have the \"completion\" command for such programs because it will allow the completion of flags and of arguments (if provided by the program).\n\n@scop can you confirm this is what you were hoping for?\n\n**Testing done**\n\n```\n# Here is a program with no sub-cmds\n$ cat tests/minimal.go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/spf13/cobra\"\n)\n\nvar rootCmd = &cobra.Command{\n\tUse: \"prog\",\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tfmt.Println(\"value:\", value)\n\t\tfmt.Println(\"args:\", args)\n\t},\n}\n\nvar value string\n\nfunc main() {\n\trootCmd.Flags().StringVarP(&value, \"value\", \"e\", \"\", \"value\")\n\trootCmd.Execute()\n}\n\n$ go build -o minimal ./tests/minimal.go\n\n$ ./minimal\nvalue:\nargs: []\n$ ./minimal arg1\nvalue:\nargs: [arg1]\n$ ./minimal arg1 arg2\nvalue:\nargs: [arg1 arg2]\n$ ./minimal arg1 arg2 --value 1\nvalue: 1\nargs: [arg1 arg2]\n\n# Notice no 'completion' command visible\n$ ./minimal -h\nUsage:\n prog [flags]\n\nFlags:\n -h, --help help for prog\n -e, --value string value\n\n# But the completion command does exist\n$ ./minimal completion -h\nGenerate the autocompletion script for prog for the specified shell.\nSee each sub-command's help for details on how to use the generated script.\n\nUsage:\n prog completion [command]\n\nAvailable Commands:\n bash Generate the autocompletion script for bash\n fish Generate the autocompletion script for fish\n powe\n...[truncated]"}, "repo": "spf13/cobra", "task_type": "edit2ripple", "version": 1} diff --git a/bench/arb/extdev/scripts/consistent_raw.py b/bench/arb/extdev/scripts/consistent_raw.py new file mode 100644 index 0000000..9cfc7df --- /dev/null +++ b/bench/arb/extdev/scripts/consistent_raw.py @@ -0,0 +1,65 @@ +"""Copy ARB raw records for PRs whose git-reconstructed diff equals the GitHub PR diff. + +`arb backfill-git-raw` diffs `baseRefOid..headRefOid` (git_raw.py: `git diff --name-status --find-renames base head`). +GitHub's PR file list is the merge-base (three-dot) diff. The two agree exactly when baseRefOid is an ancestor of +headRefOid; otherwise the two-dot diff also contains every base-branch change made after the PR branched (pilot: +hono #5233 GraphQL changedFiles=2, git diff=311 files). Keep a PR only if base is an ancestor of head AND the git file +count equals GraphQL `changedFiles`. Writes pull_requests/pull_files/pull_commits/commit_details/pull_file_summary +for kept PRs into --out// and a consistency_summary.json with drop counts. +""" +from __future__ import annotations + +import argparse +import json +import subprocess +from collections import Counter +from pathlib import Path + +FILES = ("pull_requests.jsonl", "pull_files.jsonl", "pull_file_summary.jsonl", "pull_commits.jsonl", "commit_details.jsonl") + + +def pr_num(rec): + return int(rec.get("pr_number") or (rec.get("data") or {}).get("number")) + + +def main() -> int: + p = argparse.ArgumentParser() + p.add_argument("--raw", type=Path, required=True) + p.add_argument("--out", type=Path, required=True) + p.add_argument("--repos-dir", type=Path, required=True) + p.add_argument("--repo", action="append", required=True) + a = p.parse_args() + total = {} + for repo in a.repo: + slug = repo.replace("/", "__", 1) + src, dst, wt = a.raw / slug, a.out / slug, a.repos_dir / slug + prs = {pr_num(r): r["data"] for r in map(json.loads, open(src / "pull_requests.jsonl"))} + files = {pr_num(r): r["data"] for r in map(json.loads, open(src / "pull_files.jsonl"))} + keep, why = set(), Counter() + for n, pr in prs.items(): + if n not in files: + why["no_git_backfill"] += 1 + continue + r = subprocess.run(["git", "-C", str(wt), "merge-base", "--is-ancestor", pr["baseRefOid"], pr["headRefOid"]], capture_output=True) + if r.returncode == 1: + why["base_not_ancestor_of_head"] += 1 + continue + if r.returncode != 0: + why["ancestry_unknown"] += 1 + continue + if len(files[n]) != int(pr.get("changedFiles") or -1): + why["file_count_mismatch"] += 1 + continue + keep.add(n) + dst.mkdir(parents=True, exist_ok=True) + for name in FILES: + rows = [l for l in open(src / name) if l.strip() and pr_num(json.loads(l)) in keep] + (dst / name).write_text("".join(rows)) + total[repo] = {"pull_requests": len(prs), "kept": len(keep), "dropped": dict(why)} + (dst / "consistency_summary.json").write_text(json.dumps(total[repo], indent=2) + "\n") + print(json.dumps(total, indent=2)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/bench/arb/extdev/scripts/crawl_repo.sh b/bench/arb/extdev/scripts/crawl_repo.sh new file mode 100755 index 0000000..1cc6cee --- /dev/null +++ b/bench/arb/extdev/scripts/crawl_repo.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Per-repo raw crawl: full clone (so backfill diffs are local), ARB GraphQL PR metadata, ARB backfill-git-raw. +# Usage: crawl_repo.sh OWNER/NAME LIMIT. Needs GH_TOKEN or GITHUB_TOKEN. Work dir: $ARB_WORK/extdev/work +# (ARB_WORK is run.sh's work dir, default ~/.cache/cgraph-arb); ARB is expected at $ARB_WORK/arb. +set -uo pipefail +repo="$1"; limit="$2" +ARB_WORK="${ARB_WORK:-$HOME/.cache/cgraph-arb}" +HERE="$(cd "$(dirname "$0")" && pwd)" +W="$ARB_WORK/extdev/work"; slug="${repo/\//__}" +export PYTHONPATH="$ARB_WORK/arb/src" PYTHONHASHSEED=0 +retry() { "$@" || { echo "retry after exit $?: $*" >&2; "$@"; }; } +mkdir -p "$W/logs" +cd "$W" +[[ -d "git_raw_repos/$slug/.git" ]] || retry git clone --quiet --no-checkout "https://github.com/$repo.git" "git_raw_repos/$slug" +retry python3 "$HERE/fetch_pr_metadata.py" --raw raw --repo "$repo" --limit-prs "$limit" +retry python3 -m agent_retrieval_bench.cli backfill-git-raw --raw raw --repo "$repo" --repos-dir git_raw_repos > "logs/backfill_$slug.json" +echo "DONE $repo" diff --git a/bench/arb/extdev/scripts/fetch_pr_metadata.py b/bench/arb/extdev/scripts/fetch_pr_metadata.py new file mode 100644 index 0000000..35f3c47 --- /dev/null +++ b/bench/arb/extdev/scripts/fetch_pr_metadata.py @@ -0,0 +1,46 @@ +"""Write ARB raw pull_requests.jsonl using ARB's own GraphQL crawl query, without per-PR REST calls. + +ARB's `crawl` (crawler.crawl_repo) fetches merged PRs with crawler._fetch_merged_prs_graphql and then +spends 3+N REST calls per PR (files, review comments, commits, per-commit details). This driver performs +only the GraphQL step and writes the identical pull_request record crawl_repo writes; file, commit and +commit-detail records are then filled from git by `arb backfill-git-raw` (no REST). + +Usage: PYTHONPATH=/src python3 fetch_pr_metadata.py --raw DIR --repo OWNER/NAME --limit-prs N +""" +from __future__ import annotations + +import argparse +import json +import sys +from pathlib import Path + +from agent_retrieval_bench.crawler import _fetch_merged_prs_graphql, _pull_request_key, _upsert_jsonl +from agent_retrieval_bench.github_api import GitHubAPI +from agent_retrieval_bench.io import repo_slug, utc_now, write_json + + +def main() -> int: + p = argparse.ArgumentParser() + p.add_argument("--raw", type=Path, required=True) + p.add_argument("--repo", required=True) + p.add_argument("--limit-prs", type=int, required=True) + p.add_argument("--page-size", type=int, default=50) + p.add_argument("--max-changed-files", type=int, default=20) # crawl's default (cli.py crawl --max-changed-files) + a = p.parse_args() + api = GitHubAPI() + assert api.authenticated, "set GITHUB_TOKEN" + owner, name = a.repo.split("/", 1) + repo_dir = a.raw / repo_slug(a.repo) + fetched_at = utc_now() + fetched = _fetch_merged_prs_graphql(api, owner, name, None, a.limit_prs, a.page_size, a.max_changed_files) + records = [{"type": "pull_request", "repo": a.repo, "fetched_at": fetched_at, "data": pr} for pr in fetched["accepted"]] + _upsert_jsonl(repo_dir / "pull_requests.jsonl", records, _pull_request_key) + summary = {k: fetched[k] for k in ("source", "seen", "skipped", "existing_skipped", "cursor", "rate_limit")} + summary.update({"repo": a.repo, "accepted": len(records), "limit_prs": a.limit_prs, "max_changed_files": a.max_changed_files, "fetched_at": fetched_at}) + write_json(repo_dir / "metadata_fetch_summary.json", summary) + print(json.dumps(summary), file=sys.stderr) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/bench/arb/extdev/scripts/finalize.py b/bench/arb/extdev/scripts/finalize.py new file mode 100644 index 0000000..983ab40 --- /dev/null +++ b/bench/arb/extdev/scripts/finalize.py @@ -0,0 +1,145 @@ +"""Post-miner selection for the extdev set: ARB leakage filter, edit2ripple test-only policy, per-repo cap, schema parity. + +Inputs are ARB miner outputs (samples.jsonl written by mine-code2test-prs / mine-edit2ripple with corpus gates on). +Every step is deterministic. Rows are ordered by PR number descending (default --order recency) or by the miners' +sample_sort_key (--order miner); per-repo selection keeps the first rows in that order. + +1. ARB leakage: drop rows where dataset_validity.detect_query_leakage(...)["fatal"] (FATAL_LEAKAGE_TYPES) or + baseline.query_has_leakage(...) (the check eval-baseline uses to skip a sample) is true. +2. edit2ripple only: test-only-gold share <= 25% (released v2_edit2ripple selection_summary.json strict25_policy, + max_test_only_ratio 0.25); drops the last test-only rows in the chosen order. +2b. Optional fixed --per-repo-limit (first N per repo in the chosen order), applied before step 2; for edit2ripple + at most floor(max_test_only_ratio * N) of a repo's N rows may have test-only gold. +3. Per-repo cap: largest c with every repo <= c and c <= 25% of the task total; keeps each repo's first c rows. +4. Schema parity with released rows: code2test gets top-level query_provenance="pr_summary" (released rows carry it; + baseline.query_provenance defaults code2test to the same value). edit2ripple keeps the miner's audit block with + verdict "pending" and a note (no human audit was done). +""" +from __future__ import annotations + +import argparse +import json +import math +from collections import Counter, defaultdict +from pathlib import Path + +from agent_retrieval_bench import baseline +from agent_retrieval_bench.dataset_validity import detect_query_leakage +from agent_retrieval_bench.filters import is_test_file + +AUDIT_NOTE = "extdev: no human audit; ARB miner filters + corpus gates + ARB fatal-leakage filter only" + + +def read(path: Path) -> list[dict]: + return [json.loads(l) for l in path.read_text().splitlines() if l.strip()] + + +def cap_rows(rows: list[dict], share: float) -> tuple[list[dict], int]: + by_repo: dict[str, list[dict]] = defaultdict(list) + for r in rows: + by_repo[r["repo"]].append(r) + best = 0 + for c in range(1, max((len(v) for v in by_repo.values()), default=0) + 1): + total = sum(min(len(v), c) for v in by_repo.values()) + if c <= share * total + 1e-9: + best = c + keep = {id(r) for v in by_repo.values() for r in v[:best]} + return [r for r in rows if id(r) in keep], best + + +def main() -> int: + p = argparse.ArgumentParser() + p.add_argument("--task", choices=("code2test", "edit2ripple"), required=True) + p.add_argument("--samples", type=Path, required=True) + p.add_argument("--out", type=Path, required=True, help="benchmark dir, e.g. data/benchmark/v2_code2test") + p.add_argument("--repo-share", type=float, default=0.25) + p.add_argument("--max-test-only-ratio", type=float, default=0.25) + p.add_argument("--order", choices=("recency", "miner"), default="recency", + help="row order for per-repo selection: recency = PR number descending (the order ARB's miners walk PRs), " + "miner = the miners' audit-priority sample_sort_key (biased to multi-file non-test gold)") + p.add_argument("--per-repo-limit", type=int, help="keep at most N rows per repo (first N in miner order), applied before the test-only policy") + a = p.parse_args() + rows = read(a.samples) + if a.order == "recency": + rows.sort(key=lambda r: (-int((r.get("metadata") or {}).get("pr") or 0), r["id"])) + funnel = {"mined_with_corpus_gates": Counter(r["repo"] for r in rows)} + leak_drop: Counter = Counter() + kept = [] + for r in rows: + diag = detect_query_leakage(r) + if diag["fatal"] or baseline.query_has_leakage(r, baseline.query_text_for_eval(r)): + leak_drop.update(t for t, f in ((x["type"], x["fatal"]) for x in diag["flags"]) if f) + continue + kept.append(r) + rows = kept + funnel["after_arb_leakage_filter"] = Counter(r["repo"] for r in rows) + def test_only(r): + g = r["gold"].get("files") or [] + return bool(g) and all(is_test_file(x) for x in g) + if a.per_repo_limit: + # edit2ripple: at most floor(ratio * limit) test-only-gold rows per repo, so the test-only policy holds + # per repo and globally instead of being enforced by dropping rows from whichever repos sort last. + test_quota = math.floor(a.max_test_only_ratio * a.per_repo_limit) if a.task == "edit2ripple" else a.per_repo_limit + seen: Counter = Counter() + seen_test: Counter = Counter() + limited = [] + for r in rows: + if seen[r["repo"]] >= a.per_repo_limit: + continue + if a.task == "edit2ripple" and test_only(r): + if seen_test[r["repo"]] >= test_quota: + continue + seen_test[r["repo"]] += 1 + limited.append(r) + seen[r["repo"]] += 1 + rows = limited + funnel[f"after_per_repo_limit_{a.per_repo_limit}"] = Counter(r["repo"] for r in rows) + test_only_dropped = 0 + cap = None + for _ in range(20): + if a.task == "edit2ripple": + while rows and sum(map(test_only, rows)) / len(rows) > a.max_test_only_ratio: + idx = max(i for i, r in enumerate(rows) if test_only(r)) + rows.pop(idx) + test_only_dropped += 1 + before = len(rows) + rows, cap = cap_rows(rows, a.repo_share) + if len(rows) == before: + break + funnel["after_test_only_policy_and_repo_cap"] = Counter(r["repo"] for r in rows) + for r in rows: + if a.task == "code2test": + r["query_provenance"] = "pr_summary" + else: + r["audit"] = {"notes": AUDIT_NOTE, "verdict": "pending"} + a.out.mkdir(parents=True, exist_ok=True) + body = "".join(json.dumps(r, ensure_ascii=False, sort_keys=True) + "\n" for r in rows) + (a.out / "samples.jsonl").write_text(body) + (a.out / f"{a.task}.jsonl").write_text(body) + manifest = { + "name": f"v2_{a.task}", + "schema": "arb_extdev_v2", + "task_type": a.task, + "sample_count": len(rows), + "repo_counts": dict(sorted(Counter(r["repo"] for r in rows).items())), + "task_counts": {a.task: len(rows)}, + "paths": {"benchmark": f"data/benchmark/v2_{a.task}", "corpus": f"data/corpus/v2_{a.task}"}, + "selection": { + "fatal_leakage_dropped_by_type": dict(leak_drop), + "test_only_dropped": test_only_dropped, + "test_only_ratio": (sum(map(test_only, rows)) / len(rows)) if a.task == "edit2ripple" and rows else None, + "repo_cap": cap, + "repo_share": a.repo_share, + "per_repo_limit": a.per_repo_limit, + "order": a.order, + }, + "funnel": {k: dict(sorted(v.items())) for k, v in funnel.items()}, + "audit": AUDIT_NOTE, + } + (a.out / "manifest.json").write_text(json.dumps(manifest, indent=2, sort_keys=True) + "\n") + print(json.dumps(manifest, indent=2, sort_keys=True)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/bench/arb/score.py b/bench/arb/score.py index d60a16f..3eb3bd7 100644 --- a/bench/arb/score.py +++ b/bench/arb/score.py @@ -7,7 +7,7 @@ the stored top-20 ranking against the released corpus file texts), so CGraph and the reproduced baselines are packed by exactly the same code. -Usage: score.py --arb-src DIR --data DIR --out results.json METHOD=DETAILS_DIR ... +Usage: score.py --arb-src DIR --data DIR --out results.json [--tasks TASK ...] METHOD=DETAILS_DIR ... where DETAILS_DIR holds ``_details.jsonl`` (CGraph) or ``__details.jsonl`` files (pass ``METHOD=DIR:suffix``). """ @@ -42,19 +42,19 @@ def mean(values: list[float]) -> float: return sum(values) / len(values) if values else 0.0 -def merged_manifest(data: Path, bcy_curve) -> dict[tuple[str, str], Path]: +def merged_manifest(data: Path, bcy_curve, tasks: tuple[str, ...]) -> dict[tuple[str, str], Path]: manifest: dict[tuple[str, str], Path] = {} - for task in POSITIVE_TASKS: + for task in tasks: for key, rel in bcy_curve.load_corpus_manifest(data / "corpus" / f"v2_{task}" / "corpus_manifest.jsonl").items(): manifest[key] = data.parent / rel return manifest -def score_method(details: list[dict[str, Any]], cache, bcy_curve) -> dict[str, Any]: +def score_method(details: list[dict[str, Any]], cache, bcy_curve, tasks: tuple[str, ...]) -> dict[str, Any]: positives = [d for d in details if d.get("gold_files")] bcy = bcy_curve.evaluate_run("method", "", Path("."), positives, cache, BUDGETS) out: dict[str, Any] = {} - groups = {"overall": positives, **{t: [d for d in positives if d["task_type"] == t] for t in POSITIVE_TASKS}} + groups = {"overall": positives, **{t: [d for d in positives if d["task_type"] == t] for t in tasks}} for name, rows in groups.items(): bcy_row = bcy["overall"] if name == "overall" else bcy["by_task"].get(name, {}) out[name] = { @@ -65,6 +65,10 @@ def score_method(details: list[dict[str, Any]], cache, bcy_curve) -> dict[str, A return out +def given_groups(tasks: tuple[str, ...]) -> tuple[str, ...]: + return ("overall", *(t for t in ("comment2context", "edit2ripple") if t in tasks)) + + def given_files(sample: dict[str, Any]) -> set[str]: """Files the query itself hands the agent: comment2context's given file, edit2ripple's anchor.""" query = sample.get("query") or {} @@ -75,7 +79,7 @@ def given_files(sample: dict[str, Any]) -> set[str]: return set() -def score_given_excluded(details: list[dict[str, Any]], samples: dict[str, Any], cache, bcy_curve) -> dict[str, Any]: +def score_given_excluded(details: list[dict[str, Any]], samples: dict[str, Any], cache, bcy_curve, tasks: tuple[str, ...]) -> dict[str, Any]: """Every method scored identically on its stored top 20 with the query's given/anchor file removed. Only the top 20 of each ranking is stored, so after removal a list can hold 19 files: @@ -89,7 +93,7 @@ def score_given_excluded(details: list[dict[str, Any]], samples: dict[str, Any], positives.append({**d, "top_files": [p for p in d.get("top_files") or [] if p not in drop]}) bcy = bcy_curve.evaluate_run("method", "", Path("."), positives, cache, BUDGETS) out: dict[str, Any] = {} - for name in ("overall", "comment2context", "edit2ripple"): + for name in given_groups(tasks): rows = positives if name == "overall" else [d for d in positives if d["task_type"] == name] bcy_row = bcy["overall"] if name == "overall" else bcy["by_task"].get(name, {}) @@ -126,10 +130,10 @@ def hit20(d: dict[str, Any]) -> bool: } -def render_markdown(result: dict[str, Any]) -> str: +def render_markdown(result: dict[str, Any], tasks: tuple[str, ...]) -> str: cols = (*RANK_KEYS, *(f"BCY@{b // 1000}k" for b in BUDGETS)) lines: list[str] = [] - for group in ("overall", *POSITIVE_TASKS): + for group in ("overall", *tasks): lines += [f"### {group}", "", "| Method | n | " + " | ".join(cols) + " |", "|---|---:|" + "---:|" * len(cols)] for label, entry in result["methods"].items(): row = entry["metrics"][group] @@ -143,7 +147,7 @@ def render_markdown(result: dict[str, Any]) -> str: "| Method | Group | n | Recall@20 (lower bound) | MRR@20 | BCY@8k |", "|---|---|---:|---:|---:|---:|", ] - for group in ("overall", "comment2context", "edit2ripple"): + for group in given_groups(tasks): for label, entry in result["methods"].items(): row = entry["given_excluded"][group] lines.append( @@ -173,15 +177,23 @@ def main(argv: list[str] | None = None) -> int: parser.add_argument("--out", type=Path, required=True) parser.add_argument("--markdown", type=Path, help="Also write the tables as Markdown.") parser.add_argument("--split", choices=sorted(SPLITS), default="all", help="Score only the dev or held-out repos (DEV_REPOS).") + parser.add_argument( + "--tasks", + nargs="+", + choices=POSITIVE_TASKS, + default=list(POSITIVE_TASKS), + help="Positive tasks the dataset holds (default all four); use for a dataset with only some tasks.", + ) parser.add_argument("methods", nargs="+", help="LABEL=DIR (CGraph layout) or LABEL=DIR:suffix (ARB baseline layout)") args = parser.parse_args(argv) + tasks = tuple(t for t in POSITIVE_TASKS if t in args.tasks) sys.path.insert(0, str(args.arb_src / "src")) from agent_retrieval_bench import bcy_curve # noqa: PLC0415 - cache = bcy_curve.CorpusFileCache(merged_manifest(args.data, bcy_curve)) + cache = bcy_curve.CorpusFileCache(merged_manifest(args.data, bcy_curve, tasks)) samples = { row["id"]: row - for task in POSITIVE_TASKS + for task in tasks for row in read_jsonl(args.data / "benchmark" / f"v2_{task}" / "samples.jsonl") } result: dict[str, Any] = {"methods": {}} @@ -189,7 +201,7 @@ def main(argv: list[str] | None = None) -> int: label, location = spec.split("=", 1) directory, _, suffix = location.partition(":") details: list[dict[str, Any]] = [] - for task in (*POSITIVE_TASKS, "abstention"): + for task in (*tasks, "abstention"): name = f"{task}_{suffix}_details.jsonl" if suffix else f"{task}_details.jsonl" path = Path(directory) / name if path.exists(): @@ -198,8 +210,8 @@ def main(argv: list[str] | None = None) -> int: parser.error(f"{path} missing") details = [d for d in details if SPLITS[args.split](d["repo"])] entry = { - "metrics": score_method(details, cache, bcy_curve), - "given_excluded": score_given_excluded(details, samples, cache, bcy_curve), + "metrics": score_method(details, cache, bcy_curve, tasks), + "given_excluded": score_given_excluded(details, samples, cache, bcy_curve, tasks), } if any(d.get("no_gold") for d in details): entry["selective"] = selective(details) @@ -213,7 +225,7 @@ def main(argv: list[str] | None = None) -> int: args.out.parent.mkdir(parents=True, exist_ok=True) args.out.write_text(json.dumps(result, indent=2, sort_keys=True) + "\n", encoding="utf-8") if args.markdown: - args.markdown.write_text(render_markdown(result), encoding="utf-8") + args.markdown.write_text(render_markdown(result, tasks), encoding="utf-8") return 0