We wrote down what we were going to measure, then measured it.
Anyone can publish a number. The question is whether the sample was chosen before or after somebody saw the score. Ours was chosen before, and you do not have to take our word for it: the commit that froze the sample is older than the commit that holds the results, and both are in a public repository you can clone and check with git log.
- PROTOCOL.md the protocol, written first
- sample.v7.frozen.json the frozen sample, committed before the run
- indexability.v7.json which answers were in the index at all, measured before the run
- results.v7.json the results, committed unedited afterwards
Every figure we measured is read from a committed results file at build time: this run for the headline, and the earlier runs for the figures sections 3 and 8 keep published. None of our own results is typed into the page by hand, and a test fails the build if what you see here stops matching what those files say. Two numbers are exceptions and both say so where they appear: the comparison rates further down are quoted from published papers and linked to them.
What we measured
105 issues were selected from 7 public repositories across 5 languages, and 92 of them scored. Watari read each issue title and body, nothing else, and searched a single workspace holding all 7 repositories at once. Ground truth is the file the maintainer changed in the merged fix.
What was measured is the product as it was deployed on the day of the run, not a build made for the benchmark. The results file records the exact commit, and lists every way the offline harness that ran the cases differs from production.
- File Match at rank 1
87.0%
80 of 92 · 95% CI 78.6% to 92.4%
The top ranked file is one the merged fix actually changed.
- File Match in the top 5
89.1%
82 of 92 · 95% CI 81.1% to 94.0%
A changed file appears somewhere in the five locations returned.
- Repository routing at rank 1
97.8%
90 of 92
7 repositories share one workspace, so the search has to pick the right repository before it can pick a file.
- Line overlap at rank 1
71.4%
35 of 49
Its own smaller denominator: only cases whose ground-truth file is byte identical between the indexed commit and the fix, so the rest cannot be scored at line level.
- File Match at rank 1, every exclusion counted as a miss
76.2%
80 of 105 · 95% CI 67.2% to 83.3%
13 cases were excluded, 1 because the fix creates a file that cannot exist in the indexed tree and 12 because extraction split the issue into several bugs or none. This counts all 13 against us.
Why you can believe this one
Every case above is out-of-sample. All 7 repositories are new to this benchmark, and not one of them was examined while choosing any change we have shipped.
The previous run measured 62.6% (67 of 107, 95% interval 53.2% to 71.2%) across 8 other repositories. This run measures 87.0% (80 of 92, 95% interval 78.6% to 92.4%) on cases that share no repository with it. This run is higher, and the two 95% intervals do not overlap: this run's lower bound, 78.6%, is above the previous run's upper bound, 71.2%. It is also a different and smaller sample, 7 repositories against 8 and 92 scored cases against 107, and every one of its cases was new to it. It measures the product as deployed on its own run date, and it is not evidence for any particular change. We wrote down before this run that its figure would replace the last one whichever way it moved, and it has.
An earlier run reported 64.3% (36 of 56) and we published it as a ceiling, because the change it measured had been chosen by looking at those same cases. That is why it was never the figure to quote. It is not withdrawn.
The interval is the other thing to read. Sample size is the only lever on it, and at 92 scored cases it is 13.8 points wide. That is still wide, and we would rather show you a wide interval than a point estimate without one.
What we knew before we ran it
A localizer cannot return a file it never indexed. Checking that after reading the misses is the wrong order: a check run afterwards can only be used to excuse them. So the check runs first, and its result is committed next to the frozen sample, before any case is scored. In 86 of the 92 scored cases the answer is somewhere in the index. In 6 it is not:
- jupyterlab/jupyterlab#19731 .github/workflows/linuxjs-tests.yml
- OpenRefine/OpenRefine#8011 .github/workflows/pull_request_e2e.yml, .github/workflows/snapshot_release.yml
- OpenRefine/OpenRefine#7303 .github/workflows/pull_request_server.yml
- atuinsh/atuin#2816 systemd/atuin-server.service
- gradio-app/gradio#13848 .github/actions/install-all-deps/action.yml
- grafana/k6#6202 .github/workflows/xk6.yml
They are scored as misses anyway, as they were in every earlier run. Dropping them would give 93.0% (80 of 86), and that is a diagnostic we use to decide what to index next, not a result. A customer whose bug lives in a file we do not read gets a wrong answer from us, and our reason for it is not their problem.
The spread, including the worst repository
This run shares no case with the previous one, so there is no like-for-like case comparison to show you. What there is instead is spread. Across 7 repositories the best scores 13 of 13 and the worst 10 of 14, on jupyterlab/jupyterlab. An aggregate that hides a weak repository is not a summary, so the per-repository split is printed under the table below and in the results file.
Repository routing is 90 of 92. 7 repositories share one workspace here, so the search has to pick the right repository before it can pick a file.
13 of the 105 selected cases are not scored: 1 because the merged fix creates a file that cannot exist in the tree we indexed, and 12 because extraction read the issue as several bugs or none, which is a sampled model call and varies between runs. Counting all 13 as misses gives 76.2% (80 of 105), which is on this page for exactly that reason.
Every case, including the ones we got wrong
All 92 scored cases. Each row links to the public issue, shows the file Watari ranked first, and shows the file the maintainer actually changed. Per repository: jupyterlab 10 of 14 · streamlit 14 of 15 · hugo 11 of 13 · OpenRefine 9 of 12 · atuin 11 of 13 · gradio 12 of 12 · k6 13 of 13.
jupyterlab/jupyterlab
10 of 14 hits
| Issue | Watari returned | The fix changed | Result |
|---|---|---|---|
| #20027 | packages/csvviewer-extension/src/searchprovider.ts | packages/csvviewer-extension/src/searchprovider.ts, packages/csvviewer/src/widget.ts | hit |
| #18623 | scripts/update_e2e_snapshots.py | .github/workflows/galata-update-v2.yml, scripts/unpack_snapshots.py | missnot retrieved |
| #19964 | packages/console/src/panel.ts | packages/console/src/panel.ts | hit |
| #19942 | packages/application/src/utils.ts | packages/application/src/utils.ts | hit |
| #18462 | packages/notebook/src/searchprovider.ts | packages/notebook/src/searchprovider.ts | hit |
| #19731 | .yarnrc.yml | .github/workflows/linuxjs-tests.yml | missnot retrieved |
| #18109 | packages/services/src/builder/index.ts | packages/services/package.json, packages/services/src/builder/index.ts, packages/services/src/manager.ts, packages/services/tsconfig.json, packages/translation-extension/src/index.ts | hit |
| #19721 | packages/rendermime/src/renderers.ts | packages/coreutils/src/lru.ts, packages/rendermime/src/registry.ts, packages/rendermime/src/renderers.ts | hit |
| #19611 | packages/notebook/src/widget.ts | packages/application/src/dockpanel.ts | missnot retrieved |
| #17303 | packages/notebook/src/panel.ts | packages/notebook/src/panel.ts | hit |
| #19675 | packages/notebook-extension/src/index.ts | packages/notebook-extension/src/index.ts | hit |
| #19608 | jupyterlab/extensions/pypi.py | jupyterlab/extensions/pypi.py | hit |
| #19722 | examples/example_check.py | packages/services/examples/browser/src/comm.ts | missnot retrieved |
| #17955 | pyproject.toml | packages/completer/src/default/inlinehistoryprovider.ts, pyproject.toml | hit |
streamlit/streamlit
14 of 15 hits
| Issue | Watari returned | The fix changed | Result |
|---|---|---|---|
| #17494 | frontend/lib/src/components/widgets/Slider/Slider.tsx | e2e_playwright/st_slider.py, e2e_playwright/st_slider_test.py, frontend/lib/src/components/widgets/Slider/Slider.tsx | hit |
| #17402 | frontend/utils/src/browser/index.ts | frontend/lib/src/util/utils.ts, frontend/utils/src/browser/index.ts | hit |
| #17216 | lib/streamlit/components/v2/__init__.py | lib/streamlit/components/v2/__init__.py, lib/streamlit/components/v2/component_manager.py, lib/streamlit/components/v2/component_registry.py | hit |
| #17298 | lib/streamlit/__init__.py | lib/streamlit/__init__.py, lib/streamlit/command_suggestions.py | hit |
| #17309 | frontend/lib/src/components/elements/DeckGlJsonChart/styled-components.ts | e2e_playwright/st_pydeck_chart.py, e2e_playwright/st_pydeck_chart_test.py, frontend/lib/src/components/elements/DeckGlJsonChart/styled-components.ts | hit |
| #17249 | lib/streamlit/testing/v1/app_test.py | lib/streamlit/testing/v1/app_test.py | hit |
| #17195 | frontend/lib/src/components/widgets/DataFrame/DataFrame.tsx | e2e_playwright/st_dataframe_selections_test.py, frontend/lib/src/components/widgets/DataFrame/DataFrame.tsx | hit |
| #17093 | lib/streamlit/runtime/state/session_state.py | e2e_playwright/widget_state.py, e2e_playwright/widget_state_test.py, lib/streamlit/runtime/state/session_state.py | hit |
| #17107 | frontend/lib/src/components/elements/Dialog/Dialog.tsx | frontend/lib/src/components/elements/Dialog/Dialog.tsx | hit |
| #17082 | frontend/app/src/components/GlobalHotkeys/GlobalHotkeys.tsx | frontend/app/src/components/GlobalHotkeys/GlobalHotkeys.tsx | hit |
| #14782 | frontend/lib/src/components/widgets/DataFrame/columns/LinkColumn.ts | frontend/lib/src/components/widgets/DataFrame/columns/LinkColumn.ts | hit |
| #17011 | lib/streamlit/runtime/fragment.py | e2e_playwright/st_dialog.py, e2e_playwright/st_dialog_test.py, lib/streamlit/elements/dialog_decorator.py, lib/streamlit/runtime/fragment.py | hit |
| #2975 | lib/streamlit/runtime/scriptrunner/script_runner.py | lib/streamlit/runtime/scriptrunner/script_runner.py | hit |
| #17029 | lib/streamlit/elements/metric.py | lib/streamlit/elements/metric.py | hit |
| #16909 | frontend/lib/src/components/widgets/DataFrame/columns/NumberColumn.ts | Makefile, e2e_playwright/st_data_editor_editing_test.py, frontend/.yarn/patches/@glideapps-glide-data-grid-npm-6.0.4-alpha24-9c1a40557b.patch | missnot retrieved |
gohugoio/hugo
11 of 13 hits
| Issue | Watari returned | The fix changed | Result |
|---|---|---|---|
| #15449 | hugolib/site_render.go | hugolib/site_render.go | hit |
| #15444 | tpl/cast/docshelper.go | docs/data/docs.yaml, tpl/cast/docshelper.go | hit |
| #12838 | hugolib/hugo_sites_build.go | hugolib/hugo_sites_build.go | hit |
| #15403 | tpl/collections/where_test.go | .github/workflows/test.yml, htesting/test_helpers.go | missnot retrieved |
| #15389 | tpl/tplimpl/templatestore.go | tpl/tplimpl/templatestore.go | hit |
| #14044 | resources/page/page_markup.go | resources/page/page_markup.go | hit |
| #15322 | tpl/compare/compare.go | common/hreflect/convert.go, tpl/collections/reflect_helpers.go, tpl/collections/where.go, tpl/compare/compare.go | hit |
| #15330 | hugolib/hugo_sites_build.go | hugolib/pages_capture.go | missnot retrieved |
| #15253 | config/allconfig/load.go | config/allconfig/allconfig.go, config/allconfig/load.go | hit |
| #15234 | tpl/tplimpl/templatetransform.go | tpl/tplimpl/templatetransform.go | hit |
| #15237 | common/hstore/scratch.go | common/hstore/scratch.go | hit |
| #15223 | commands/config.go | commands/config.go | hit |
| #15207 | hugolib/content_map_page_contentnodeshifter.go | hugolib/content_map_page_contentnodeshifter.go, hugolib/doctree/nodeshifttree.go | hit |
OpenRefine/OpenRefine
9 of 12 hits
| Issue | Watari returned | The fix changed | Result |
|---|---|---|---|
| #7704 | main/src/com/google/refine/exporters/CsvExporter.java | main/src/com/google/refine/exporters/CsvExporter.java | hit |
| #8011 | .github/workflows/pull_request_e2e.yml | .github/workflows/pull_request_e2e.yml, .github/workflows/snapshot_release.yml | hit |
| #7894 | packaging/pom.xml | packaging/pom.xml | hit |
| #7141 | main/webapp/modules/core/scripts/facets/list-facet.js | main/webapp/modules/core/scripts/facets/list-facet.js | hit |
| #7892 | extensions/wikibase/src/org/openrefine/wikibase/qa/scrutinizers/ItemRequiresScrutinizer.java | extensions/wikibase/src/org/openrefine/wikibase/qa/scrutinizers/ItemRequiresScrutinizer.java | hit |
| #7831 | extensions/wikibase/src/org/openrefine/wikibase/schema/strategies/LaxValueMatcher.java | extensions/wikibase/src/org/openrefine/wikibase/schema/strategies/LaxValueMatcher.java | hit |
| #7902 | server/pom.xml | server/src/com/google/util/logging/IndentingLayout.java, server/src/log4j2.properties | missnot retrieved |
| #7872 | extensions/wikibase/src/org/openrefine/wikibase/exporters/SchemaExporter.java | extensions/wikibase/src/org/openrefine/wikibase/exporters/SchemaExporter.java | hit |
| #7303 | readme_template.md | .github/workflows/pull_request_server.yml | missnot retrieved |
| #7808 | extensions/wikibase/src/org/openrefine/wikibase/qa/scrutinizers/FileNameScrutinizer.java | extensions/wikibase/src/org/openrefine/wikibase/qa/scrutinizers/FileNameScrutinizer.java | hit |
| #6745 | main/pom.xml | main/pom.xml | hit |
| #3012 | main/webapp/modules/core/scripts/dialogs/expression-preview-dialog.js | extensions/jython/src/com/google/refine/jython/JythonEvaluable.java, main/src/com/google/refine/commands/expr/PreviewExpressionCommand.java | missin top 5 |
atuinsh/atuin
11 of 13 hits
| Issue | Watari returned | The fix changed | Result |
|---|---|---|---|
| #2816 | systemd/atuin-server.service | systemd/atuin-server.service | hit |
| #4263 | crates/atuin-pty-proxy/src/pty_proxy.rs | crates/atuin-pty-proxy/src/pty_proxy.rs, crates/atuin-pty-proxy/src/runtime.rs | hit |
| #4225 | crates/atuin-daemon/src/lib.rs | crates/atuin/src/command/client/daemon.rs | missin top 5 |
| #4220 | crates/atuin-pty-proxy/src/pty_proxy.rs | crates/atuin-pty-proxy/Cargo.toml, crates/atuin-pty-proxy/src/pty_proxy.rs | hit |
| #4149 | crates/atuin/src/shell/atuin.zsh | crates/atuin/src/shell/atuin.bash, crates/atuin/src/shell/atuin.zsh | hit |
| #2512 | crates/atuin/src/command/client/wrapped.rs | crates/atuin-history/src/stats.rs, crates/atuin/src/command/client/wrapped.rs | hit |
| #4063 | crates/atuin-server/src/router.rs | Cargo.toml, crates/atuin-server/src/router.rs | hit |
| #3758 | crates/atuin/src/shell/atuin.zsh | crates/atuin/src/shell/atuin.zsh | hit |
| #2884 | crates/atuin/Cargo.toml | crates/atuin-server/Cargo.toml, crates/atuin/Cargo.toml | hit |
| #3603 | crates/atuin-client/src/ordering.rs | crates/atuin-client/src/database.rs, crates/atuin-client/src/ordering.rs | hit |
| #3761 | crates/atuin/src/shell.rs | .github/workflows/rust.yml, crates/atuin/Cargo.toml, crates/atuin/src/shell.rs | hit |
| #3471 | crates/atuin-client/src/record/sync.rs | crates/atuin-client/src/record/encryption.rs | miss |
| #3695 | crates/atuin/src/command/mod.rs | crates/atuin-pty-proxy/src/pty_proxy.rs, crates/atuin-pty-proxy/src/runtime.rs, crates/atuin/src/command/mod.rs | hit |
gradio-app/gradio
12 of 12 hits
| Issue | Watari returned | The fix changed | Result |
|---|---|---|---|
| #13881 | js/accordion/Index.svelte | demo/accordion_tab_switch/run.py, js/accordion/Index.svelte, js/core/src/dependency.ts, js/core/src/init.svelte.ts, js/tabs/Index.svelte | hit |
| #13943 | js/markdown-code/MarkdownCode.svelte | js/markdown-code/MarkdownCode.svelte, js/markdown-code/utils.ts | hit |
| #13939 | js/markdown-code/MarkdownCode.svelte | js/markdown-code/MarkdownCode.svelte, js/markdown-code/utils.ts | hit |
| #13897 | js/audio/interactive/InteractiveAudio.svelte | js/audio/interactive/InteractiveAudio.svelte, js/audio/streaming/StreamAudio.svelte, js/core/src/lang/en.json | hit |
| #13923 | gradio/processing_utils.py | gradio/processing_utils.py | hit |
| #13900 | js/audio/interactive/InteractiveAudio.svelte | client/js/src/utils/submit.ts, js/audio/interactive/InteractiveAudio.svelte | hit |
| #13898 | js/audio/shared/audioBufferToWav.ts | js/audio/shared/audioBufferToWav.ts | hit |
| #13856 | gradio/processing_utils.py | gradio/components/audio.py, gradio/processing_utils.py | hit |
| #13869 | js/core/src/dependency.ts | js/core/src/dependency.ts | hit |
| #13818 | js/core/src/MountCustomComponent.svelte | js/core/src/MountCustomComponent.svelte, js/preview/src/svelte_runtime_entry.js | hit |
| #13131 | js/core/src/MountCustomComponent.svelte | js/core/src/MountCustomComponent.svelte, js/preview/src/svelte_runtime_entry.js | hit |
| #13848 | .github/actions/install-all-deps/action.yml | .github/actions/install-all-deps/action.yml | hit |
grafana/k6
13 of 13 hits
| Issue | Watari returned | The fix changed | Result |
|---|---|---|---|
| #6150 | internal/output/prometheusrw/sigv4/sigv4.go | internal/output/prometheusrw/remotewrite/config.go, internal/output/prometheusrw/sigv4/const.go, internal/output/prometheusrw/sigv4/sigv4.go, internal/output/prometheusrw/sigv4/tripper.go | hit |
| #2951 | lib/executor/ramping_arrival_rate.go | lib/executor/ramping_arrival_rate.go | hit |
| #5012 | internal/js/modules/k6/browser/common/http.go | internal/js/modules/k6/browser/common/http.go, internal/js/modules/k6/browser/common/network_manager.go | hit |
| #6353 | internal/js/modules/k6/websockets/websockets.go | internal/js/modules/k6/websockets/websockets.go | hit |
| #6320 | internal/js/modules/k6/webcrypto/crypto.go | internal/js/modules/k6/webcrypto/crypto.go | hit |
| #5328 | internal/js/modules/k6/browser/common/browser.go | internal/js/modules/k6/browser/common/browser.go | hit |
| #6317 | lib/netext/httpext/tracer.go | lib/netext/httpext/tracer.go | hit |
| #6354 | lib/netext/httpext/digest_transport.go | go.mod, lib/netext/httpext/digest_transport.go, lib/netext/httpext/request.go | hit |
| #425 | internal/output/influxdb/config.go | internal/output/influxdb/config.go | hit |
| #1185 | js/modules/k6/http/request.go | js/modules/k6/http/request.go | hit |
| #4657 | internal/log/file.go | internal/log/file.go | hit |
| #6181 | metrics/sink.go | metrics/sink.go | hit |
| #6202 | .github/workflows/xk6.yml | .github/workflows/xk6.yml | hit |
Feature requests, measured the same way
Watari also maps small, specific feature requests, the kind that name a change to code that already exists, and drafts a pull request for them. So we measured that too, under its own protocol written before the sample was chosen: 40 issues from 4 of the repositories an earlier bug run used, each labelled a feature by its own maintainers, scored against the files their merged pull request changed.
On the 28 Watari judged specific enough to map, the top-ranked file was one the maintainers changed 67.9% of the time (19 of 28, 95% interval 49.3% to 82.1%), and one appeared in the top five 85.7% of the time (24 of 28). Counting every excluded or declined case as a miss gives 47.5% (19 of 40).
That is below the bug figure, and the intervals overlap, so at these sample sizes the two cannot be told apart. The feature-request run is older than the bug run and measured the product as deployed on its own run date, so the two are not a like-for-like comparison. The sample is small and says so. One more thing it showed: 6 of the 40 were read by extraction as bugs, not feature requests. In the product those are handled as bugs, and if you disagree with that call, the Mismapped credit covers it.
results.v5.json every case, committed unedited, after sample.v5.frozen.json.
What this does not prove
This measures one step of six: finding the file. It says nothing about whether the draft pull request we write is any good, whether the tests we add are meaningful, or whether the customer-facing RCA reads well. Those can be shown and timestamped, and they are, on the walkthrough page. They cannot be scored against ground truth a third party already produced, so we do not put a number on them.
How to read 87.0% (80 of 92)
Localizing a bug from a report written by a user is much harder than from an issue written by a developer with a stack trace attached. On the two published academic benchmarks built from user-written reports, the best reported top-1 file accuracy is 41.6% on LinuxFLBench (250 real user-submitted bug reports) and 28.5% on MULocBench (1,100 issues across 46 projects). Both are quoted from those papers. They are the two figures on this page we did not measure.
One difference runs in our favour and should be said out loud: both of those hand the model the repository. We searched 7 repositories at once and had to pick the right one first, which is the routing figure above.
The earlier runs stay published
Version 1 · Earlier run47.1% (8 of 17), 95% interval 26.2% to 69.0%
Version 2 · Earlier run58.9% (33 of 56), 95% interval 45.9% to 70.8%
Version 3 · Ceiling, in-sample64.3% (36 of 56), 95% interval 51.2% to 75.5%
Version 4 · Earlier run56.5% (61 of 108), 95% interval 47.1% to 65.5%
Version 5 · Feature requests67.9% (19 of 28), 95% interval 49.3% to 82.1%
Version 6 · Earlier run62.6% (67 of 107), 95% interval 53.2% to 71.2%
Version 7 · Standing run87.0% (80 of 92), 95% interval 78.6% to 92.4%
Version 1 of this protocol measured 47.1% (8 of 17) with a 95% interval of 26.2% to 69.0%. Version 2 measured 58.9% (33 of 56), 45.9% to 70.8%. Version 3 measured 64.3% (36 of 56) on the same cases as version 2 against a fuller index, and was published as a ceiling because the change it measured had been chosen by looking at those cases. Version 4 measured 56.5% (61 of 108), 47.1% to 65.5%, on repositories nobody here had read, and was the standing figure until version 6 replaced it. Version 6 measured 62.6% (67 of 107), 53.2% to 71.2%, on the product exactly as deployed, and was the standing figure until the run above replaced it. None of the five is revised or withdrawn, and all their results files sit in the same public repository. A wider sample was the point of the second version, a fuller index the point of the third, repositories nobody here had read the point of the fourth, the product exactly as deployed the point of the sixth, and the product as deployed today, on repositories new again, the point of this one.