diff --git a/docs/language_status/README.md b/docs/language_status/README.md index f3a907b5..b898c58f 100644 --- a/docs/language_status/README.md +++ b/docs/language_status/README.md @@ -62,7 +62,7 @@ epic #813), not that no cases exist. | **[assembly](assembly.md)** | production | line_exclusive | 42/52 | 148 | 83 | **written** | | **[c](c.md)** | production | standard_block | 50/52 | 42 | 86 | **written** | | **[cobol](cobol.md)** | production | positional_anchored | 48/52 | 62 | 82 | **written** | -| cpp | production | standard_block | 52/52 | 42 | 76 | not written | +| **[cpp](cpp.md)** | production | standard_block | 52/52 | 46 | 76 | **written** | | csharp | production | standard_block | 51/52 | 44 | 106 | not written | | css | production | standard_block | 30/48 | 18 | 74 | not written | | dart | production | standard_block | 51/52 | 91 | 86 | not written | diff --git a/docs/language_status/cpp.md b/docs/language_status/cpp.md new file mode 100644 index 00000000..a2497262 --- /dev/null +++ b/docs/language_status/cpp.md @@ -0,0 +1,390 @@ +# C++ — Structural Signature Coverage + +Snapshot generated 2026-08-21 against `main`. Source: `LANGUAGE_DEFINITIONS["cpp"]` in +`gitgalaxy/standards/language_standards.py`, `tests/extraction/languages/test_cpp.py` / +`test_cpp_strict.py`, closed GitHub issues, and +[`gitgalaxy-raw-output`](https://github.com/squid-protocol/gitgalaxy-raw-output). Re-run the +`language-status` skill's data-gathering commands before trusting these numbers if this doc looks +old relative to `last_updated` below. This doc covers sections 1-8 only (documentation, not engine +changes) — a §9 measured-accuracy section using this sweep's own tri-comparison data is being +appended separately by the main session. + +## 1. At a glance + +| Field | Value | +|---|---| +| `_meta.status` | `production` | +| `_meta.target_version` | C++23 (Modules, Concepts, Coroutines, Ranges, `std::print`) | +| `_meta.blueprint_version` | v5.0 | +| `_meta.last_updated` | 2026-02-18 | +| `lexical_family` | `standard_block` (`//` line comments + `/* */` block comments, non-nesting) | +| Structural signature keys wired | 52 / 52 (0 explicit `None` — see §4 for what's absent instead) | +| Extraction-gauntlet tests (`test_cpp.py`) | 46 | +| Strict-signature tests (`test_cpp_strict.py`) | 76 | +| Total dedicated C++ test cases | 122 | + +Note on the "52/52" figure: cpp carries every key in the universal 52-key baseline schema +(`how_to_add_a_language.md`'s OUTPUT SCHEMA), all wired to a real regex — none set to explicit +`None`. That's different from `hardcoded_secrets` (present in the schema template but only +actually wired for a small handful of languages, e.g. `solidity`/`yaml`) and the opt-in AI/ML +extension pack (`llm_api`/`dl_frameworks`/etc., currently `python`/`javascript`/`typescript` +only) — cpp simply doesn't carry either, which is correct per the extension-pack doc's own +opt-in rule, not a gap. See §4. + +## 2. Identification surface + +- **Extensions:** `.cpp .cc .cxx .c++ .hpp .hh .hxx .h++ .tpp .inc .inl .ipp .cp .C .H` — every + common source/header suffix across GNU, MSVC, and legacy UNIX-casing conventions, plus + template-implementation (`.tpp`/`.ipp`) and generic-include (`.inc`/`.inl`) suffixes. +- **Exact filenames:** none. +- **Discriminators:** `.cpp`, `.cc`, `.cxx`, `CMakeLists.txt`, `conanfile.txt`, `vcpkg.json`, + `Makefile`, `BUILD.bazel`, `WORKSPACE` — build-system/package-manifest anchors used to + disambiguate ambiguous shared extensions (`.h`, `.inc`) from plain `c`. +- **Shebangs:** `cling`, `cint` — C++ interpreter/REPL front-ends. + +## 3. What GitGalaxy detects + +Grouped by the phase headers `language_standards.py`/`how_to_add_a_language.md` use. Description +is what C++'s *actual* regex matches, not the generic cross-language definition. + +**Topology & structure** +| Key | What it captures for C++ | +|---|---| +| `branch` | `if else switch case default for while do catch break continue goto co_yield co_await`, `&& \|\| ?` — includes C++20 coroutine jumps, excludes exceptions (those live in `panics_and_aborts`) | +| `args` | Parameter blocks of free functions/methods/lambdas, including class-qualified operator names (`TargetClass::operator=`), bounded 2-level nested template args, and out-of-line definitions; the parameter-list span is its own capture group (#1209) so the arg counter isolates just `(...)`, not the whole name+template+params match | +| `structural_boundaries` | `namespace using class struct enum union template typename concept requires auto return void inline virtual explicit friend module export import typedef` | +| `func_start` | A ten-stage pipeline (attributes → linkage/storage modifiers → return type with bounded 2-level template nesting and pointer/reference handling on either side of whitespace → operator/destructor/qualified-name capture → parameter block via 1-level nesting trick → trailing `const`/`noexcept`/`override`/trailing-return-type → K&R/constructor-initializer-list gap → opening `{`); explicitly rejects control-flow keywords (`if`, `for`, `if constexpr`, etc.) as false function names and shields against crossing into `#`-preprocessor lines mid-signature | +| `class_start` | `class struct union enum class enum struct`, optional `export`/template prefix (2-level nested template default-arg tolerant), optional `[[attribute]]`/`__attribute__` step-over, single capture group for the entity name only — deliberately does not capture the base-class/interface list (§5) | + +**Safety & risk** +| Key | What it captures for C++ | +|---|---| +| `safety` | `try catch finally`, `std::unique_ptr/shared_ptr/weak_ptr`, `override final noexcept static_assert assert`, `std::optional/expected/span/variant`, `std::lock_guard`, `std::atomic` | +| `safety_bypasses` | `std::any`, `void*`/`void *` (any spacing), `catch (...)` | +| `high_risk_execution` | `system memcpy memset abort exit std::terminate longjmp setjmp` | +| `io` | `std::fstream/ifstream/ofstream/filesystem`, `fopen fclose fread fwrite`, `socket recv send`, `asio::`, `curl_easy_perform`, `std::cin` | +| `api` | `export module` / `export import` / `export class`, `public:`, `__declspec(dllexport)`, `__attribute__((visibility("default")))`, or a bare line-leading `export` not followed by `module` | +| `state_mutation` | `mutable std::move std::exchange std::swap std::atomic`, bare assignment `=` (excluding `==`/`!=`/`<=`/`>=`), reference-bind `&` (excluding `& const`), `++ --`, compound assignment operators | +| `dead_code` | `//` or `/*` immediately followed by `if for while auto class struct std::cout std::print printf void int return` — covers both comment styles (a `standard_block` requirement) | +| `doc` | `///`, `/**`, Doxygen `@param/@return/@brief/@details/@tparam` and their `\param`-style backslash equivalents | +| `test` | `TEST TEST_F TEST_CASE SECTION REQUIRE CHECK EXPECT_* ASSERT_*`, `Catch:: GTest` — anchored to GTest/Catch2 macro shapes to avoid prose collisions | + +**Architecture & domain sensors** +| Key | What it captures for C++ | +|---|---| +| `concurrency` | `std::thread/jthread/mutex/future/promise/async/latch/barrier/condition_variable/semaphore`, `co_await`, `std::coroutine_handle` | +| `ui_framework` | `Q_OBJECT QWidget wxFrame ImGui:: Fl_Window`, `slots:`, `signals:` | +| `closures` | Lambda capture-list `[...]` through an optional template-arg list, optional parameter list, optional `mutable`/`constexpr`/`consteval`/`noexcept`, optional trailing return type, up to the opening `{` | +| `globals` | `extern static thread_local inline constexpr` (with `static` excluding `static_assert`), or a line-leading `static`/`extern` typed declaration with assignment | +| `decorators` | `[[attribute]]`-style C++11/20 attribute annotations | +| `generics` | `template<...>`, `concept`, `requires` | +| `comprehensions` | `std::ranges:: std::views:: views:: std::transform/accumulate/reduce/for_each/filter`, or `\| std::views::` pipeline syntax | +| `scientific` | `std::cmath/complex/linalg/mdspan`, `Eigen:: blaze::`, `std::simd`, `__m128/__m256/__m512`, `std::numbers::` | +| `reflection_metaprogramming` | `if constexpr`, `if consteval`, `std::enable_if/is_same/any_cast/bit_cast`, `decltype`, `sizeof...`, `#define ` | +| `import` | Line-leading `#include <...>`/`#include "..."`, `import name;`, `export import name;` | +| `_dependency_capture` | Extracts the exact include path or module name from the four import forms above | +| `ownership` | `@author`/`\author`/`Author:`/`Created by:`/`Copyright` (case-insensitive, captures the rest of the line) | + +**Specialized subsystems** +| Key | What it captures for C++ | +|---|---| +| `planned_debt` / `fragile_debt` | Shared `GLOBAL_` TODO/FIXME-family markers | +| `spec_exposure` | `[SPEC-123]`, `[spec ...]`, `[audit ...]` traceability tags (bounded quantifiers, ReDoS-hardened per #713) | +| `ssr_boundaries` | `FCGI_Accept render_template Inja:: ctemplate::` | +| `events` | `emit signal slot notify publish subscribe boost::signals2` | +| `dependency_injection` | `boost.di fruit:: Inject IServiceCollection` | +| `macros` | Line-leading `#define/undef/if/elif/else/endif/pragma/warning/error` | +| `pointers` | `->`, `uintptr_t intptr_t ptrdiff_t size_t`, lookbehind-guarded `&var`/`*var` dereference forms that exclude ordinary multiplication/logical-AND | +| `memory_alloc` | `new malloc calloc realloc aligned_alloc mmap alloca` | +| `inline_asm` | `__asm__`/`asm`/`__asm` followed by `(` (optionally with `volatile`/`__volatile__`) or by `{` | + +**Resource management & stability** +| Key | What it captures for C++ | +|---|---| +| `telemetry` | `log/logger/LOGGER/spdlog/glog/syslog` `.info/.error/.warn/.debug/.trace` | +| `debug_prints` | `std::cout/cerr/clog printf fprintf vprintf puts putchar std::print std::println` | +| `explicit_casts` | `static_cast dynamic_cast reinterpret_cast const_cast bit_cast`, functional-cast-style single-identifier templates followed by `(` (e.g. `narrow_cast(x)`, deliberately excluding plain declarations like `std::vector`), and C-style casts including pointer casts (`(int*)ptr`) | +| `panics_and_aborts` | `throw abort exit _Exit quick_exit std::terminate longjmp` | +| `thread_sleeps` | `sleep delay usleep nanosleep std::this_thread::sleep_for` | +| `bitwise_ops` | `^`, `~` (not preceded by `=`/`!`), `<<= >>= &= \|= ^=` — bare `<< >>` deliberately excluded to avoid `std::cout`/`std::cin` stream-operator false positives | +| `sync_locks` | `mutex lock synchronized Semaphore std::lock_guard/scoped_lock/unique_lock mtx_lock` (case-insensitive) | +| `immutability_locks` | `const constexpr consteval constinit final readonly Immutable` | +| `cleanup` | `delete free close fclose dispose shutdown std::destroy reset` immediately followed by `(` | +| `encapsulation` | `private: protected: internal:` | +| `listeners` | `on addEventListener subscribe connect handler callback` | +| `test_skip` | `GTEST_SKIP test.skip it.skip`, `mock(`, `fake(` | + +**Hybrid domain sensors** +| Key | What it captures for C++ | +|---|---| +| `serialization_parsing` | `nlohmann::json rapidjson boost::archive ParseFromString SerializeToString` | +| `regex_execution` | `std::regex std::regex_match/search/replace` | +| `time_date_logic` | `std::chrono::system_clock/steady_clock/duration`, `std::time_t`, `std::localtime` | +| `ipc_rpc_bridges` | `boost::interprocess mmap shm_open pipe fork grpc::ServerBuilder` | + +## 4. What GitGalaxy explicitly does not track + +Unlike many languages in this repo, cpp has **zero keys explicitly set to `None`** — every key in +the universal 52-key baseline schema is wired to a real regex. What cpp *doesn't* carry is instead +simply absent from its `rules` dict entirely (no key, no comment explaining why), which is a +different and normal situation for two categories of key: + +- **`hardcoded_secrets`** — present in the schema template's OUTPUT SCHEMA comment block, but in + practice only actually wired for a small number of languages (`solidity`, `yaml`, and a couple + others) across the whole registry — not a universal-baseline expectation despite appearing in + the template. cpp not having it is consistent with the vast majority of other languages, not a + cpp-specific gap. +- **The AI/ML extension pack** (`llm_api`, `llm_orchestrator`, `llm_vector_store`, `ml_traditional`, + `dl_frameworks`, `hardware_bridge`, `cryptography`, `rce_funnel`, `exfiltration_camouflage`, + `memory_scraping`, `lazy_evaluation`, `vectorized_math`, `_named_token_capture`) — explicitly + opt-in per `how_to_add_a_language.md`'s "Optional: AI/ML & Literate-Programming Extension Pack" + section, currently carried only by `python`/`javascript`/`typescript`. C++ is a plausible host + for some of this (e.g. it does have ML/scientific-computing use), but no one has opted it in yet + — not evaluated in this pass as a gap since it's out of scope for a documentation-only sweep. + +## 5. Known limitations (accepted, not fixed) + +Two gaps are deliberately documented rather than fixed, via `known_limitation`-named tests in +`test_cpp.py`: + +1. **`func_start` has no string/comment awareness of its own.** Function-shaped text inside a raw + string literal (`R"(...)"`, commonly used to embed SQL/regex/JSON) that happens to land at true + line start still matches as if it were a real function. This is the same architectural gap + already confirmed for JavaScript/TypeScript template literals, Java text blocks, Go raw + strings, Rust raw strings, and C# verbatim strings (recurring bug class 3 in + `tests/extraction/how_to_harden_extraction.md`) — cpp is a sixth language hitting it. cpp + currently routes through Mode B (`_slice_by_braces`), which is gated to `javascript`/ + `typescript` only for the mitigation; not fixed here, tracked as future work in the epic. +2. **`class_start` never captures the base-class/interface list.** `struct Foo : public Base {` + only captures `"Foo"` — nothing for `"Base"`. This is the original, pre-existing design (only + one capture group exists at all), unlike `java`/`csharp`/`python`'s `class_start` where a + second capture group for the base list already exists. Not treated as a gap: `class_start`'s + contract here is anchoring the START position, and the base-list was never part of it. + +**Six additional real, currently open engine defects** were found in a companion tri-comparison- +ledger sweep on 2026-08-21 and filed the same day — not yet fixed as of this doc's snapshot: + +- **[#2009](https://github.com/squid-protocol/gitgalaxy/issues/2009)** — `func_start` recall gap + on functions whose constructor-initializer-list span exceeds the rule's bounded length cap. +- **[#2010](https://github.com/squid-protocol/gitgalaxy/issues/2010)** — `func_start` recall gap + on template-return-type conversion operators. +- **[#2011](https://github.com/squid-protocol/gitgalaxy/issues/2011)** — `class_start` false + positive on forward declarations (`class Foo;`) that never actually define the class body. +- **[#2012](https://github.com/squid-protocol/gitgalaxy/issues/2012)** — `args` counting bugs + (parameter-count miscounts on specific real-world signature shapes). +- **[#2013](https://github.com/squid-protocol/gitgalaxy/issues/2013)** — `func_start` false + positive on a lambda defined inside a constructor's initializer list. +- **[#2014](https://github.com/squid-protocol/gitgalaxy/issues/2014)** — a tree-sitter tooling + defect (not a GitGalaxy engine defect), noted here for completeness since it surfaced in the same + cpp-focused sweep. + +## 6. Test depth + +- **Extraction gauntlet** (`func_start`/`args`/`class_start`/`_dependency_capture`): 46 tests in + `tests/extraction/languages/test_cpp.py` — valid/invalid/pathological cases per rule, plus the + ReDoS-immunity sweep and the two known-limitation tests above. Fully migrated to the + per-language file (epic #813, issue #821) — cpp's entries were removed from the four old + monolithic gauntlet files (`test_function_extraction_strict.py` etc.) when this file was added, + so nothing is left behind there for cpp. +- **Strict signature suite** (all other wired keys): 76 tests in + `tests/extraction/languages/test_cpp_strict.py` — positive/negative match, cross-rule ambiguity + (`explicit_casts` vs. `pointers`, `bitwise_ops` vs. `std::cout`, `func_start` vs. macros, an + intentional-double-classification sweep), ReDoS-immunity checks, and per-signature deep-case + batteries for `branch`/`args`/`func_start`/`class_start`/`structural_boundaries` (epic #518, + issue #774). + +## 7. Relevant closed work + +**Epic-level hardening passes:** +- [#774](https://github.com/squid-protocol/gitgalaxy/issues/774) (PR + [#787](https://github.com/squid-protocol/gitgalaxy/pull/787)) — Strict parsing tests for C++ + structural signatures (epic #518): built the full per-signature positive/negative/ambiguity/ + ReDoS template cpp had never received, folding in the handful of pre-existing scattered + regression tests (`test_cpp_macro_multiline_spiral`, the C++ half of + `test_thermodynamic_operator_collisions`) rather than duplicating them. +- [#821](https://github.com/squid-protocol/gitgalaxy/issues/821) (PR + [#882](https://github.com/squid-protocol/gitgalaxy/pull/882)) — Extraction hardening for C++ + (epic #813): built the valid/invalid/pathological gauntlet for `func_start`/`args`/ + `class_start`/`_dependency_capture`, migrated off the old monolithic dict files. + +**Real bugs found and fixed along the way:** +- [#1263](https://github.com/squid-protocol/gitgalaxy/issues/1263) (PR + [#1281](https://github.com/squid-protocol/gitgalaxy/pull/1281)) — `func_start` missed + pointer/reference return types in the common `Type *name()`/`Type * name()` form (only the + glued `Type* name()` form worked), and mishandled operator/destructor names; also the origin of + the class-qualified out-of-line operator support (`TargetClass::operator=`) now present in both + `func_start` and `args`. +- [#1265](https://github.com/squid-protocol/gitgalaxy/issues/1265) (PR + [#1280](https://github.com/squid-protocol/gitgalaxy/pull/1280)) — confirmed the *measurement + tool's* ground truth was broken, not GitGalaxy: `tree_sitter_accuracy_audit.py`'s `_get_node_name` + had no handling for C/C++-family grammars' `function_definition` node (which carries no `name` + field directly), making every C/C++ function appear unnamed to the audit regardless of what + GitGalaxy itself found. Fixing the measurement tool is what made #1263's real (much smaller) gap + visible in the first place. +- [#1719](https://github.com/squid-protocol/gitgalaxy/issues/1719) — `func_start` had no support + for type-conversion operators containing alphanumeric/namespaced names (`operator bool`, + `operator Variant`, `operator ::AABB() const`) or the functor call operator (`operator()`); + fixed on `main` (commit `424bdeae`). +- [#1720](https://github.com/squid-protocol/gitgalaxy/issues/1720) (PR + [#1764](https://github.com/squid-protocol/gitgalaxy/pull/1764)) — the shared macro-shielding + logic (`_build_brace_safe_stream`) assumed the first branch of any `#if`/`#ifndef` was always the + active code and blindly shielded out the `#else` branch, hiding real implementations that live + there instead. +- [#1718](https://github.com/squid-protocol/gitgalaxy/issues/1718) (PR + [#1761](https://github.com/squid-protocol/gitgalaxy/pull/1761)) — modern C++ digit separators + (`512'000`) were misread by the shared literal-shielding logic as an opening single-quote char + literal, shielding out every function between the separator and the next stray apostrophe. + +**Cross-language fixes that happened to touch cpp along the way:** +- [#713](https://github.com/squid-protocol/gitgalaxy/issues/713) — fixed `spec_exposure`'s + unbounded `[^\]]*` ReDoS shape, copy-pasted across 28 languages including cpp. +- [#1209](https://github.com/squid-protocol/gitgalaxy/issues/1209) — wrapped the parameter-list + span of `args` in its own capture group across languages (including cpp) so detector.py's + counter isolates just `(...)` instead of falling back to the whole name+params match, which + overcounted every zero/one-arg signature by +1 (the same shape as Python's #1199). + +Search performed via `gh issue list --search 'in:title "Extraction hardening: cpp"'` / +`'in:title "Strict parsing tests: `cpp`"'` / `'in:title cpp'` plus the issues named in this doc's +generation prompt (#1263, #1265, #2009-#2014) (2026-08-21). + +## 8. Real-world evidence (`gitgalaxy-raw-output`) + +Four repos from the `v2.4.7` batch, chosen for a spread across game-engine, computer-vision, +and classic small-C-library shapes: + +- **[`godot`](https://github.com/squid-protocol/gitgalaxy-raw-output/blob/main/v2.4.7/godot/godot_galaxy_llm.md)** + — a large, heavily templated modern C++ game engine (rendering, physics, scripting bridge); + a good stress test for `func_start`'s template/attribute/pointer-reference handling at scale. + Scanned in 48.96s. +- **[`opencv`](https://github.com/squid-protocol/gitgalaxy-raw-output/blob/main/v2.4.7/opencv/opencv_galaxy_llm.md)** + — a long-lived computer-vision library with heavy operator-overload and template usage + (`Mat`, matrix math), a natural fit for exercising the operator/conversion-operator paths in + `func_start`/`args`. Scanned in 30.19s. +- **[`curl`](https://github.com/squid-protocol/gitgalaxy-raw-output/blob/main/v2.4.7/curl/curl_galaxy_llm.md)** + — small, canonical, mostly-C networking library routed under the shared `.h`/discriminator + surface; a low-noise contrast case against the two large C++-heavy engines above. Scanned in + 3.33s. +- **[`sqlite`](https://github.com/squid-protocol/gitgalaxy-raw-output/blob/main/v2.4.7/sqlite/sqlite_galaxy_llm.md)** + — another small, classic C systems library; useful as a second low-noise baseline with a very + different domain (embedded database engine vs. networking). Scanned in 5.62s. + +Each `_galaxy_llm.md` is the human-readable architectural brief; `_galaxy_audit.json.gz` and +`_galaxy_sbom.json.gz` in the same directory carry the raw per-file signature counts and SBOM if +deeper inspection is needed. +## 9. Tri-comparison findings (GitGalaxy vs. tree-sitter vs. ctags) + +A 2026-08-21 tri-comparison-ledger-sweep investigated every unvalidated discrepancy shape for +`cpp` in `docs/self_scan/tri_comparison_ledger.json` (14 shapes total). Unlike the measured- +accuracy section other language docs may carry (a single tool scored against a privileged ground +truth), this comparison has no privileged tool — see `tests/tools/tri_comparison_reconcile.py`'s +own module docstring for why. All 14 shapes are now `status: "validated"`; the summary below is +built entirely from that investigation's evidence trail, not from memory of it. + +### Summary + +| | Occurrences investigated | Confirmed GitGalaxy defects | Confirmed comparison-tooling defects | Confirmed ctags-structural limitations | +|---|---|---|---|---| +| cpp | ~590 (raw ledger counts across 14 shapes) | 6 (filed as issues) | 3 (fixed same session) | 2 (documented, not fixable here) | + +Six real GitGalaxy engine defects were confirmed and filed in this sweep — more than any other +language this sweep methodology has been run against so far, though that reflects C++'s syntactic +complexity (templates, operator overloading, out-of-class definitions, GNU extensions in real +corpus code) at least as much as it reflects anything specific to this scanner's cpp rules. + +### Where GitGalaxy wins outright + +- **Macro-invocation false positives ARE caught correctly in most cases** — GitGalaxy's own + func_start regex does not get fooled by ordinary macro calls the way ctags' parser sometimes is + (see `ctags_reader.py`'s cpp KIND MAPS bullet for the `IFACEMETHODIMP_`/`FUNC2`/`GDCLASS`-body + cases where only ctags is wrong). +- Out-of-class method definitions, once the comparison tooling itself was fixed to read them + correctly (see below), show GitGalaxy in essentially full agreement with tree-sitter's own + parse across NVDA/storage.cpp, godot/*, and mlir/flatbuffer_export.cc — thousands of real + qualified methods, zero disagreement once compared correctly. + +### Confirmed real GitGalaxy defects (filed, not yet fixed) + +All six need the full Differential Scan verification chain (extraction gauntlet tests, +`crucible_check.py` against the full ~80-repo corpus, both golden masters re-blessed) before +shipping — none were patched inline in this sweep, since each has real blast radius and/or design +questions the sweep's own investigation flagged explicitly: + +- **[#2009](https://github.com/squid-protocol/gitgalaxy/issues/2009)** — func_start misses + constructors whose member-initializer-list exceeds the regex's 500-character cap for that + clause (confirmed: a real 906-character initializer list in `mlir/flatbuffer_export.cc`). +- **[#2010](https://github.com/squid-protocol/gitgalaxy/issues/2010)** — func_start misses + conversion operators with a template/generic return type (`operator Vector()`) — the + operator-name regex branch has no support for angle-bracket generics. +- **[#2011](https://github.com/squid-protocol/gitgalaxy/issues/2011)** — class_start counts a + bare forward declaration (`class Foo;`) as a real class definition — the same + `_CLASS_START_REQUIRES_BODY_ANCHOR` guard that already protects C was never extended to cpp. + Not a trivial copy-paste fix: C++ multiple inheritance (`class Foo : public A, public B {`) + breaks the existing C-only lookahead regex, confirmed via direct testing. +- **[#2012](https://github.com/squid-protocol/gitgalaxy/issues/2012)** — args-counting reads 0 + for out-of-class methods and `operator()` overloads with real parameters, and off-by-one + overcounts a constructor with an initializer list but zero real parameters. Two sub-patterns, + possibly two root causes. +- **[#2013](https://github.com/squid-protocol/gitgalaxy/issues/2013)** — func_start false + positive: a lambda passed as a constructor argument or member-initializer-list entry + (`m_draggingState([this]() {...}),`, `std::thread([...]() {...}).detach();`) is misread as a + function definition named after the lambda's target. +- **[#2014](https://github.com/squid-protocol/gitgalaxy/issues/2014)** — not a GitGalaxy defect; + listed here for completeness since it was found in the same investigation. tree-sitter's own + shared `_get_param_count` helper (`tests/tools/tree_sitter_accuracy_audit.py`, used by the + verification tooling only) undercounts by exactly 1 for any parameter with a default value. + +### Comparison-tooling defects found and fixed in the same session + +Three bugs lived in this repo's own comparison tooling (`tests/tools/ctags_reader.py`, +`tests/tools/tri_comparison_gatherer.py`, `tests/tools/tree_sitter_accuracy_audit.py`) — not in +GitGalaxy, not in tree-sitter or ctags themselves: + +1. **ctags name/scope re-qualification** — ctags reports an out-of-class method's bare, + unqualified name plus a separate `class:`/`namespace:` scope field; GitGalaxy and tree-sitter + both read the fully-qualified identifier straight from source text. Fixed by re-joining + name+scope from ctags' own tag data (`_QUALIFY_NAME_WITH_SCOPE`, + `_cpp_qualified_name_candidates`), gated on the qualified text actually appearing in the tag's + own verbatim source line (via a new `--pattern-length-limit=0` ctags flag, since the default + ~100-char truncation was silently breaking this check on longer signatures) so an ordinary + in-class-body method — never qualified in source — isn't wrongly qualified too. This alone + resolved roughly 1000 of the original ~2170 combined occurrences behind cpp's two largest + ledger shapes. +2. **Missing enum/union ctags kinds** — `CTAGS_CLASS_KINDS["cpp"]` had neither ctags' `"u"` + (union) nor `"g"` (enum) kind mapped, so real `union Foo {...}` and `enum class Foo {...}` + definitions GitGalaxy correctly counts as classes had no ctags counterpart at all. Fixed by + adding both, with enum gated on the tag's own source line actually saying `enum class`/ + `enum struct` (`_is_cpp_unscoped_enum`) since ctags' "g" kind doesn't itself distinguish a + scoped C++11 enum from a plain, unscoped one the way GitGalaxy's own class_start regex does. + The identical gap was also found and fixed for `csharp` in the same pass (C# has no + scoped/unscoped distinction, so that fix is unconditional). +3. **Forward declarations and unscoped enums over-counted as classes by the tree-sitter walker** + — both `tri_comparison_gatherer.py`'s own walker and `tree_sitter_accuracy_audit.py`'s + `measure()` had a `lang == "c"`-only guard against counting a bodyless `class_specifier` + (forward declaration) as a real class definition, never extended to cpp despite tree-sitter-cpp + inheriting the identical grammar shape from tree-sitter-c. Separately, both walkers counted + every `enum_specifier` node unconditionally, with no gate for C++11's scoped-vs-unscoped + distinction the way GitGalaxy's own regex already has. Both fixed in both files (checking + `node.child_by_field_name("body")` and a new `_is_cpp_unscoped_enum` node-shape check, + respectively). + +### Confirmed ctags-structural limitations (not fixable in this repo) + +- ctags parses **inside C++ macro DEFINITION bodies** as if they were real, already-expanded code + — `godot/object.h`'s `GDCLASS`/`_FORCE_INLINE_`-based macros define method-shaped text that + only becomes real code once expanded at a call site elsewhere, but ctags tags the + never-actually-compiled-as-written declarator text inside the macro body anyway (9 sampled + cases, all the same macro family). +- ctags mistags a **macro used as a return-type prefix or dispatch label** as the function itself + — Windows COM's `IFACEMETHODIMP_(void) FancyZones::Run() noexcept {...}` tags `IFACEMETHODIMP_` + as a complete function and loses the real `FancyZones::Run` name entirely; the same shape hits + `godot/rendering_server_default.h`'s `FUNC2`/`FUNC3`/`FUNCRIDTEX1` macros and + `godot/gdscript_vm.cpp`'s `OPCODE`/`OPCODE_WHILE`/`OPCODE_SWITCH` bytecode-dispatch macros — the + latter is shared with GitGalaxy and tree-sitter, which independently misparse the *same* macro + invocations as function definitions (a genuine shared mistake between GitGalaxy and tree-sitter, + not real corroboration — see the ledger's own `agree[gitgalaxy,tree_sitter]_vs[ctags]` verdict). + +### Full record + +Filtered ledger: `jq '.entries | to_entries[] | select(.key | startswith("cpp/"))' +docs/self_scan/tri_comparison_ledger.json`. Rendered summary with source citations: +`docs/self_scan/tri_comparison_points_of_interest.md` (search for `cpp`). diff --git a/docs/self_scan/tri_comparison_chart.svg b/docs/self_scan/tri_comparison_chart.svg index 1778511d..6423be99 100644 --- a/docs/self_scan/tri_comparison_chart.svg +++ b/docs/self_scan/tri_comparison_chart.svg @@ -188,39 +188,43 @@ cpp -1462* +1462 -1491* +1491 -1378* +1378 - -1400/1462* - -1393/1491* - -304/1378* + +1347/1462 + +1288/1491 + +1348/1378 + +C - -149* - -171* - -56* + +149 + +65 + +65 - -149/149* - -149/171* - -54/56* + +65/149 + +65/65 + +63/65 + +T -295* +1287 -295* +1287 -295* +1287 csharp @@ -242,15 +246,15 @@ 33* 24* - -22* + +33* - -27/33* + +33/33* 24/24* -22/22* +33/33* 535* @@ -1085,17 +1089,17 @@ 2750 -Summary -- best tool per (language, metric), ranked panels only (Func/Class Precision), 30 real comparisons (1-bar groups and empty panels don't count) +Summary -- best tool per (language, metric), ranked panels only (Func/Class Precision), 32 real comparisons (1-bar groups and empty panels don't count) G -GitGalaxy best: 11 (37%) +GitGalaxy best: 11 (34%) T -tree-sitter best: 1 (3%) +tree-sitter best: 2 (6%) C -ctags best: 0 (0%) +ctags best: 1 (3%) -Ties: 18 (60%) +Ties: 18 (56%) Ranked-panel labels are matched/total; found-count panels are a single raw count, no denominator. Regenerate: tri_comparison_chart.py --all --write \ No newline at end of file diff --git a/docs/self_scan/tri_comparison_ledger.json b/docs/self_scan/tri_comparison_ledger.json index 4ab4f455..4c12bb7d 100644 --- a/docs/self_scan/tri_comparison_ledger.json +++ b/docs/self_scan/tri_comparison_ledger.json @@ -13,7 +13,7 @@ "investigated_at": "2026-08-20T00:00:00Z", "investigated_by": "Claude (Sonnet 5), direct investigation via tri-comparison-ledger-sweep", "language": "agc_assembly", - "last_reconciled_at": "2026-08-21T11:59:36Z", + "last_reconciled_at": "2026-08-21T13:27:16Z", "last_seen_count": 215, "last_seen_examples": [ { @@ -118,7 +118,7 @@ "investigated_at": "2026-08-20T00:00:00Z", "investigated_by": "Claude (Sonnet 5), direct investigation via tri-comparison-ledger-sweep", "language": "agc_assembly", - "last_reconciled_at": "2026-08-21T11:59:36Z", + "last_reconciled_at": "2026-08-21T13:27:16Z", "last_seen_count": 37, "last_seen_examples": [ { @@ -221,7 +221,7 @@ "investigated_at": "2026-08-20T22:17:39Z", "investigated_by": "Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep (direct investigation, no Gemini dispatch needed -- root cause was immediately clear from source)", "language": "apex", - "last_reconciled_at": "2026-08-21T11:59:37Z", + "last_reconciled_at": "2026-08-21T13:27:17Z", "last_seen_count": 2, "last_seen_examples": [ { @@ -260,7 +260,7 @@ "investigated_at": "2026-08-20T00:00:00Z", "investigated_by": "Claude (Sonnet 5), direct investigation via tri-comparison-ledger-sweep", "language": "assembly", - "last_reconciled_at": "2026-08-21T11:59:39Z", + "last_reconciled_at": "2026-08-21T13:27:19Z", "last_seen_count": 26, "last_seen_examples": [ { @@ -363,7 +363,7 @@ "investigated_at": "2026-08-20T00:00:00Z", "investigated_by": "Claude (Sonnet 5), direct investigation via tri-comparison-ledger-sweep", "language": "assembly", - "last_reconciled_at": "2026-08-21T11:59:39Z", + "last_reconciled_at": "2026-08-21T13:27:19Z", "last_seen_count": 7, "last_seen_examples": [ { @@ -443,7 +443,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Claude Sonnet 5 (resolved + fixed directly, no dispatch needed)", "language": "c", - "last_reconciled_at": "2026-08-21T11:59:44Z", + "last_reconciled_at": "2026-08-21T13:27:24Z", "last_seen_count": 23, "last_seen_examples": [ { @@ -557,7 +557,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Gemini (dispatched via tri-comparison-ledger-sweep), confirmed by Claude Sonnet 5", "language": "c", - "last_reconciled_at": "2026-08-21T11:59:44Z", + "last_reconciled_at": "2026-08-21T13:27:24Z", "last_seen_count": 9, "last_seen_examples": [ { @@ -662,7 +662,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Gemini (dispatched via tri-comparison-ledger-sweep), confirmed by Claude Sonnet 5", "language": "c", - "last_reconciled_at": "2026-08-21T11:59:44Z", + "last_reconciled_at": "2026-08-21T13:27:24Z", "last_seen_count": 525, "last_seen_examples": [ { @@ -776,7 +776,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Claude Sonnet 5 (resolved directly, no dispatch needed) -- corrected after cross-referencing #1837", "language": "c", - "last_reconciled_at": "2026-08-21T11:59:44Z", + "last_reconciled_at": "2026-08-21T13:27:24Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -809,7 +809,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Claude Sonnet 5 (resolved + fixed directly, no dispatch needed)", "language": "c", - "last_reconciled_at": "2026-08-21T11:59:44Z", + "last_reconciled_at": "2026-08-21T13:27:24Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -842,7 +842,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Gemini (dispatched via tri-comparison-ledger-sweep), confirmed by Claude Sonnet 5", "language": "c", - "last_reconciled_at": "2026-08-21T11:59:44Z", + "last_reconciled_at": "2026-08-21T13:27:24Z", "last_seen_count": 13, "last_seen_examples": [ { @@ -959,7 +959,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Claude Sonnet 5 (resolved directly, no dispatch needed)", "language": "c", - "last_reconciled_at": "2026-08-21T11:59:44Z", + "last_reconciled_at": "2026-08-21T13:27:24Z", "last_seen_count": 3, "last_seen_examples": [ { @@ -1010,7 +1010,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Claude Sonnet 5 (resolved + fixed directly, no dispatch needed)", "language": "c", - "last_reconciled_at": "2026-08-21T11:59:44Z", + "last_reconciled_at": "2026-08-21T13:27:24Z", "last_seen_count": 7, "last_seen_examples": [ { @@ -1097,7 +1097,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Gemini (dispatched via tri-comparison-ledger-sweep), confirmed by Claude Sonnet 5", "language": "c", - "last_reconciled_at": "2026-08-21T11:59:44Z", + "last_reconciled_at": "2026-08-21T13:27:24Z", "last_seen_count": 3, "last_seen_examples": [ { @@ -1150,7 +1150,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Claude Sonnet 5 (resolved directly, no dispatch needed)", "language": "c", - "last_reconciled_at": "2026-08-21T11:59:44Z", + "last_reconciled_at": "2026-08-21T13:27:24Z", "last_seen_count": 4, "last_seen_examples": [ { @@ -1210,7 +1210,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Gemini (dispatched via tri-comparison-ledger-sweep), confirmed by Claude Sonnet 5", "language": "c", - "last_reconciled_at": "2026-08-21T11:59:44Z", + "last_reconciled_at": "2026-08-21T13:27:24Z", "last_seen_count": 74, "last_seen_examples": [ { @@ -1325,7 +1325,7 @@ "investigated_at": "2026-08-19", "investigated_by": "gemini-3.1-pro-high (agy), dispatched via tri-comparison-ledger-sweep, self-corrected and reviewed by claude-sonnet-5", "language": "cobol", - "last_reconciled_at": "2026-08-21T11:59:49Z", + "last_reconciled_at": "2026-08-21T13:27:29Z", "last_seen_count": 19, "last_seen_examples": [ { @@ -1428,7 +1428,7 @@ "investigated_at": "2026-08-19", "investigated_by": "gemini-3.1-pro-high (agy), dispatched via tri-comparison-ledger-sweep, reviewed by claude-sonnet-5", "language": "cobol", - "last_reconciled_at": "2026-08-21T11:59:49Z", + "last_reconciled_at": "2026-08-21T13:27:29Z", "last_seen_count": 136, "last_seen_examples": [ { @@ -1531,7 +1531,7 @@ "investigated_at": "2026-08-19", "investigated_by": "gemini-3.1-pro-high (agy), dispatched via tri-comparison-ledger-sweep, reviewed by claude-sonnet-5", "language": "cobol", - "last_reconciled_at": "2026-08-21T11:59:49Z", + "last_reconciled_at": "2026-08-21T13:27:29Z", "last_seen_count": 43, "last_seen_examples": [ { @@ -1632,10 +1632,10 @@ "tree_sitter" ], "first_seen_at": "2026-08-18T22:44:22Z", - "investigated_at": null, - "investigated_by": null, + "investigated_at": "2026-08-21T00:00:00Z", + "investigated_by": "Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep", "language": "cpp", - "last_reconciled_at": "2026-08-21T11:59:54Z", + "last_reconciled_at": "2026-08-21T13:27:34Z", "last_seen_count": 2, "last_seen_examples": [ { @@ -1658,10 +1658,10 @@ } ], "metric": "existence", - "status": "unvalidated", + "status": "validated", "still_reproduces": true, "symbol_type": "class", - "verdict": null + "verdict": "Not a real existence disagreement -- a template-argument name-formatting difference in the comparison tooling. `godot/variant.h`'s `HashMapComparatorDefault` and `is_zero_constructible` are template CLASS specializations; GitGalaxy and tree-sitter both read the name WITH its template argument baked in (matching the instantiation as written in source), while ctags strips the `<...>` template-argument suffix from its own class tag name. All three tools found the exact same class definition at the exact same line -- confirmed via the sibling agree[gitgalaxy,tree_sitter]_vs[ctags] entry, which is the same pair of classes from the opposite direction. Low magnitude (2 occurrences) -- not chased to a code fix in this pass, but a plausible future micro-fix would strip a trailing `<...>` from gg/tree-sitter's class name before matching, mirroring how ctags_reader.py's operator-name normalization already handles a similar formatting mismatch." }, "cpp/class/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]": { "agreeing_tools": [ @@ -1674,11 +1674,53 @@ "ctags" ], "first_seen_at": "2026-08-18T22:44:22Z", - "investigated_at": null, - "investigated_by": null, + "investigated_at": "2026-08-21T00:00:00Z", + "investigated_by": "Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep", + "language": "cpp", + "last_reconciled_at": "2026-08-21T13:27:34Z", + "last_seen_count": 2, + "last_seen_examples": [ + { + "file_path": "godot/variant.h", + "name": "HashMapComparatorDefault", + "readings": { + "ctags": null, + "gitgalaxy": null, + "tree_sitter": 886 + } + }, + { + "file_path": "godot/variant.h", + "name": "is_zero_constructible", + "readings": { + "ctags": null, + "gitgalaxy": null, + "tree_sitter": 984 + } + } + ], + "metric": "existence", + "status": "validated", + "still_reproduces": true, + "symbol_type": "class", + "verdict": "Same template-argument name-formatting difference as the sibling agree[ctags]_vs[gitgalaxy,tree_sitter] class entry, viewed from the opposite direction -- `HashMapComparatorDefault`/`is_zero_constructible` (ctags' bare names) vs. `HashMapComparatorDefault`/`is_zero_constructible` (GitGalaxy/tree-sitter's names, template argument included). Not a real disagreement about whether these classes exist -- see the sibling entry for the full explanation." + }, + "cpp/class/existence/agree[gitgalaxy]_vs[ctags,tree_sitter]": { + "agreeing_tools": [ + "gitgalaxy" + ], + "credit_tools": [], + "debit_tools": [], + "dissenting_tools": [ + "ctags", + "tree_sitter" + ], + "first_seen_at": "2026-08-21T13:03:30Z", + "investigated_at": "2026-08-21T00:00:00Z", + "investigated_by": "Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep", "language": "cpp", - "last_reconciled_at": "2026-08-21T11:59:54Z", - "last_seen_count": 95, + "last_reconciled_at": "2026-08-21T13:27:34Z", + "last_seen_count": 84, "last_seen_examples": [ { "file_path": "godot/editor_node.h", @@ -1686,7 +1728,7 @@ "readings": { "ctags": null, "gitgalaxy": null, - "tree_sitter": 45 + "tree_sitter": null } }, { @@ -1695,7 +1737,7 @@ "readings": { "ctags": null, "gitgalaxy": null, - "tree_sitter": 46 + "tree_sitter": null } }, { @@ -1704,7 +1746,7 @@ "readings": { "ctags": null, "gitgalaxy": null, - "tree_sitter": 47 + "tree_sitter": null } }, { @@ -1713,7 +1755,7 @@ "readings": { "ctags": null, "gitgalaxy": null, - "tree_sitter": 48 + "tree_sitter": null } }, { @@ -1722,7 +1764,7 @@ "readings": { "ctags": null, "gitgalaxy": null, - "tree_sitter": 49 + "tree_sitter": null } }, { @@ -1731,7 +1773,7 @@ "readings": { "ctags": null, "gitgalaxy": null, - "tree_sitter": 50 + "tree_sitter": null } }, { @@ -1740,7 +1782,7 @@ "readings": { "ctags": null, "gitgalaxy": null, - "tree_sitter": 51 + "tree_sitter": null } }, { @@ -1749,7 +1791,7 @@ "readings": { "ctags": null, "gitgalaxy": null, - "tree_sitter": 52 + "tree_sitter": null } }, { @@ -1758,7 +1800,7 @@ "readings": { "ctags": null, "gitgalaxy": null, - "tree_sitter": 53 + "tree_sitter": null } }, { @@ -1767,15 +1809,15 @@ "readings": { "ctags": null, "gitgalaxy": null, - "tree_sitter": 54 + "tree_sitter": null } } ], "metric": "existence", - "status": "unvalidated", + "status": "validated", "still_reproduces": true, "symbol_type": "class", - "verdict": null + "verdict": "Confirmed real GitGalaxy defect, filed as https://github.com/squid-protocol/gitgalaxy/issues/2011 . GitGalaxy's own class_start regex counts a bare forward declaration (`class AudioStreamPreviewGenerator;`, godot/editor_node.h:68 and 83 more of the same shape in the same file) as if it were a real class definition -- `_CLASS_START_REQUIRES_BODY_ANCHOR` in detector.py, the exact mechanism that already guards against this for C, was never extended to cpp. This session's own tree-sitter walker (tri_comparison_gatherer.py / tree_sitter_accuracy_audit.py) had the identical `lang == \"c\"`-only gap and has been fixed here (both now check `node.child_by_field_name(\"body\") is None`); the production engine fix is deliberately NOT attempted in the same pass because C++ multiple inheritance (`class Foo : public A, public B {`) makes the existing C-only lookahead regex (which stops at the first `{`/`;`/`,`/`)`/`=`) unsafe to reuse as-is for cpp -- confirmed via direct regex testing that a real multi-inheritance class would be falsely excluded. See issue #2011 for the full design note." }, "cpp/class/existence/agree[tree_sitter]_vs[ctags,gitgalaxy]": { "agreeing_tools": [ @@ -1788,10 +1830,10 @@ "gitgalaxy" ], "first_seen_at": "2026-08-18T22:44:22Z", - "investigated_at": null, - "investigated_by": null, + "investigated_at": "2026-08-21T00:00:00Z", + "investigated_by": "Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep", "language": "cpp", - "last_reconciled_at": "2026-08-21T11:59:54Z", + "last_reconciled_at": "2026-08-21T13:27:34Z", "last_seen_count": 22, "last_seen_examples": [ { @@ -1886,10 +1928,10 @@ } ], "metric": "existence", - "status": "unvalidated", - "still_reproduces": true, + "status": "validated", + "still_reproduces": false, "symbol_type": "class", - "verdict": null + "verdict": "Confirmed real defect in this repo's own tree-sitter walker (tri_comparison_gatherer.py / tree_sitter_accuracy_audit.py), fixed in this session. tree-sitter-cpp's `enum_specifier` node covers BOTH a C++11 scoped enum (`enum class Foo {...}`) and a plain, unscoped C-style enum (`enum Foo {...}`) -- distinguishable only by whether a `class`/`struct` token is one of the node's direct children. GitGalaxy's own cpp class_start regex only counts the SCOPED form (matching real C++ semantics -- a plain enum has no scope of its own); ctags' own 'g' (enum) kind was already correctly gated the same way earlier in this same sweep (see the sibling agree[gitgalaxy,tree_sitter]_vs[ctags] class entry). This walker alone counted every enum_specifier unconditionally. Every sampled case (godot/editor_node.h's SceneNameCasing/ActionOnPlay/ActionOnStop/MenuOptions/MenuType, godot/main.h's CLIOptionAvailability) is a plain, unscoped enum. Fixed via `_is_cpp_unscoped_enum` in both walker copies (checks for a `class`/`struct` child token, cpp-only -- C has no scoped-enum syntax at all so is deliberately excluded from the gate). Confirmed fixed: this shape no longer reproduces on a fresh reconcile run after the fix." }, "cpp/function/args/agree[ctags,gitgalaxy]_vs[tree_sitter]": { "agreeing_tools": [ @@ -1902,10 +1944,10 @@ "tree_sitter" ], "first_seen_at": "2026-08-18T22:44:22Z", - "investigated_at": null, - "investigated_by": null, + "investigated_at": "2026-08-21T00:00:00Z", + "investigated_by": "Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep", "language": "cpp", - "last_reconciled_at": "2026-08-21T11:59:54Z", + "last_reconciled_at": "2026-08-21T13:27:34Z", "last_seen_count": 13, "last_seen_examples": [ { @@ -2000,10 +2042,10 @@ } ], "metric": "args", - "status": "unvalidated", + "status": "validated", "still_reproduces": true, "symbol_type": "function", - "verdict": null + "verdict": "Confirmed real tree-sitter accuracy-tool limitation, filed separately (see the sibling agree[none]_vs[ctags,gitgalaxy,tree_sitter] args entry and its referenced issue for the full writeup). tree-sitter's own parameter count (via the shared `_get_param_count` helper in tree_sitter_accuracy_audit.py, reused by tri_comparison_gatherer.py) undercounts by exactly 1 whenever a function has a parameter with a default value -- confirmed 6/6 sampled cases (save_scene_to_path, step, get_index, atr_n, atr, ObjectSignalLock), all off by exactly 1, all involving a `= default_value` parameter, ctags and GitGalaxy both correctly counting the real total. No credit_tools/debit_tools adjustment applies -- this is an args-metric shape, and apply_verified_adjustments only ever touches existence-metric precision (args scores have no equivalent verified-adjustment mechanism in this ledger's own code, see tri_comparison_ledger.py's apply_verified_adjustments docstring), so these fields would be a pure no-op here regardless of value -- left empty rather than set-but-inert, for an accurate record." }, "cpp/function/args/agree[ctags,tree_sitter]_vs[gitgalaxy]": { "agreeing_tools": [ @@ -2016,24 +2058,33 @@ "gitgalaxy" ], "first_seen_at": "2026-08-18T22:44:22Z", - "investigated_at": null, - "investigated_by": null, + "investigated_at": "2026-08-21T00:00:00Z", + "investigated_by": "Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep", "language": "cpp", - "last_reconciled_at": "2026-08-21T11:59:54Z", - "last_seen_count": 15, + "last_reconciled_at": "2026-08-21T13:27:34Z", + "last_seen_count": 60, "last_seen_examples": [ { - "file_path": "mlir/flatbuffer_export.cc", - "name": "CreateLocation", + "file_path": "NVDA/storage.cpp", + "name": "VBufStorage_buffer_t::replaceSubtrees", "readings": { - "ctags": 5, + "ctags": 1, "gitgalaxy": 0, - "tree_sitter": 5 + "tree_sitter": 1 } }, { - "file_path": "mlir/flatbuffer_export.cc", - "name": "GetStringsFromDictionaryAttr", + "file_path": "NVDA/storage.cpp", + "name": "VBufStorage_buffer_t::VBufStorage_buffer_t", + "readings": { + "ctags": 0, + "gitgalaxy": 1, + "tree_sitter": 0 + } + }, + { + "file_path": "godot/node.h", + "name": "operator()", "readings": { "ctags": 2, "gitgalaxy": 0, @@ -2041,35 +2092,35 @@ } }, { - "file_path": "mlir/flatbuffer_export.cc", - "name": "CreateOpLocation", + "file_path": "godot/node.h", + "name": "operator()", "readings": { - "ctags": 5, + "ctags": 2, "gitgalaxy": 0, - "tree_sitter": 5 + "tree_sitter": 2 } }, { - "file_path": "mlir/flatbuffer_export.cc", - "name": "MlirToFlatBufferTranslateFunction", + "file_path": "godot/node.h", + "name": "operator()", "readings": { - "ctags": 3, + "ctags": 2, "gitgalaxy": 0, - "tree_sitter": 3 + "tree_sitter": 2 } }, { - "file_path": "mlir/flatbuffer_export.cc", - "name": "MlirToFlatBufferTranslateFunction", + "file_path": "godot/node.h", + "name": "operator()", "readings": { - "ctags": 4, + "ctags": 2, "gitgalaxy": 0, - "tree_sitter": 4 + "tree_sitter": 2 } }, { - "file_path": "mlir/flatbuffer_export.cc", - "name": "GetTensorFlowNodeDef", + "file_path": "godot/variant.cpp", + "name": "operator<", "readings": { "ctags": 1, "gitgalaxy": 0, @@ -2077,8 +2128,8 @@ } }, { - "file_path": "mlir/flatbuffer_export.cc", - "name": "GetStringsFromAttrWithSeparator", + "file_path": "godot/variant.h", + "name": "operator()", "readings": { "ctags": 2, "gitgalaxy": 0, @@ -2087,37 +2138,28 @@ }, { "file_path": "mlir/flatbuffer_export.cc", - "name": "IsUnsupportedLocation", - "readings": { - "ctags": 1, - "gitgalaxy": 0, - "tree_sitter": 1 - } - }, - { - "file_path": "mlir/mlir_bridge_rollout_policy.cc", - "name": "GetMlirBridgeRolloutPolicy", + "name": "Translator::BuildBuffer", "readings": { - "ctags": 6, + "ctags": 3, "gitgalaxy": 0, - "tree_sitter": 6 + "tree_sitter": 3 } }, { - "file_path": "mlir/mlir_graph_optimization_pass.cc", - "name": "DumpModule", + "file_path": "mlir/flatbuffer_export.cc", + "name": "Translator::BuildVhloCompositeV1Op", "readings": { - "ctags": 2, + "ctags": 4, "gitgalaxy": 0, - "tree_sitter": 2 + "tree_sitter": 4 } } ], "metric": "args", - "status": "unvalidated", + "status": "validated", "still_reproduces": true, "symbol_type": "function", - "verdict": null + "verdict": "Confirmed real GitGalaxy args-counting defect, filed as https://github.com/squid-protocol/gitgalaxy/issues/2012 . Two distinct sub-patterns visible in the sample: (1) zero-undercounting for out-of-class method definitions with real parameters (VBufStorage_buffer_t::replaceSubtrees, Translator::BuildBuffer, Translator::BuildVhloCompositeV1Op, and every `operator()` call-operator overload in godot/node.h) where ctags and tree-sitter both correctly count real, non-zero parameter lists and GitGalaxy reads 0; (2) an off-by-one OVERcount for a constructor with a member-initializer-list but zero real parameters (VBufStorage_buffer_t's default constructor -- ctags/tree-sitter correctly read 0 params, GitGalaxy reads 1). Not the same shape as the func_start recall gaps in #2009/#2010 -- these are all functions GitGalaxy already finds, just with the wrong parameter count. Needs its own dedicated investigation per the issue (may be one or two root causes)." }, "cpp/function/args/agree[gitgalaxy,tree_sitter]_vs[ctags]": { "agreeing_tools": [ @@ -2130,10 +2172,10 @@ "ctags" ], "first_seen_at": "2026-08-18T22:44:22Z", - "investigated_at": null, - "investigated_by": null, + "investigated_at": "2026-08-21T00:00:00Z", + "investigated_by": "Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep", "language": "cpp", - "last_reconciled_at": "2026-08-21T11:59:54Z", + "last_reconciled_at": "2026-08-21T13:27:34Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -2147,10 +2189,10 @@ } ], "metric": "args", - "status": "unvalidated", + "status": "validated", "still_reproduces": false, "symbol_type": "function", - "verdict": null + "verdict": "Historical -- no longer reproduces as of this session's ctags_reader.py fixes (--pattern-length-limit=0 and the generalized scope-qualification logic, both part of the same fix that resolved the bulk of the existence shapes above). The single sampled occurrence (godot/variant.h's `call`, ctags=1 vs gitgalaxy=2/tree_sitter=2) was most likely a downstream symptom of the same name-qualification/pattern-truncation bug that affected existence matching generally. Kept as a historical record per this ledger's own lifecycle rules rather than deleted." }, "cpp/function/args/agree[none]_vs[ctags,gitgalaxy,tree_sitter]": { "agreeing_tools": [], @@ -2162,10 +2204,10 @@ "tree_sitter" ], "first_seen_at": "2026-08-18T22:44:22Z", - "investigated_at": null, - "investigated_by": null, + "investigated_at": "2026-08-21T00:00:00Z", + "investigated_by": "Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep", "language": "cpp", - "last_reconciled_at": "2026-08-21T11:59:54Z", + "last_reconciled_at": "2026-08-21T13:27:34Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -2179,10 +2221,10 @@ } ], "metric": "args", - "status": "unvalidated", + "status": "validated", "still_reproduces": true, "symbol_type": "function", - "verdict": null + "verdict": "A single function (NVDA/storage.cpp's `outputEscapedAttribute`, `size_t outputEscapedAttribute(wostringstream& out, const wstring& text, size_t maxLength=0)`, 3 real parameters) where all three tools disagree for two already-independently-confirmed reasons, not a new one: ctags reads the correct count (3); GitGalaxy reads 0, matching the args-undercounting defect filed as https://github.com/squid-protocol/gitgalaxy/issues/2012 ; tree-sitter reads 2, matching the default-value-parameter undercount filed as https://github.com/squid-protocol/gitgalaxy/issues/2014 (this function's third parameter, `maxLength`, has a default value -- exactly the trigger condition for that bug). Both referenced issues cover the general pattern; no new finding here beyond confirming they can compound on the same function." }, "cpp/function/existence/agree[ctags,gitgalaxy]_vs[tree_sitter]": { "agreeing_tools": [ @@ -2195,12 +2237,57 @@ "tree_sitter" ], "first_seen_at": "2026-08-19T23:28:39Z", - "investigated_at": null, - "investigated_by": null, + "investigated_at": "2026-08-21T00:00:00Z", + "investigated_by": "Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep", "language": "cpp", - "last_reconciled_at": "2026-08-21T11:59:54Z", - "last_seen_count": 8, + "last_reconciled_at": "2026-08-21T13:27:34Z", + "last_seen_count": 60, "last_seen_examples": [ + { + "file_path": "godot/gdscript_vm.cpp", + "name": "GDScriptFunction::call", + "readings": { + "ctags": 499, + "gitgalaxy": 499, + "tree_sitter": null + } + }, + { + "file_path": "godot/main.cpp", + "name": "Main::setup", + "readings": { + "ctags": 1027, + "gitgalaxy": 1027, + "tree_sitter": null + } + }, + { + "file_path": "godot/main.cpp", + "name": "Main::setup2", + "readings": { + "ctags": 3007, + "gitgalaxy": 3007, + "tree_sitter": null + } + }, + { + "file_path": "godot/main.cpp", + "name": "Main::start", + "readings": { + "ctags": 3987, + "gitgalaxy": 3987, + "tree_sitter": null + } + }, + { + "file_path": "godot/object.cpp", + "name": "Object::Connection::operator Variant", + "readings": { + "ctags": 108, + "gitgalaxy": 108, + "tree_sitter": null + } + }, { "file_path": "godot/object.h", "name": "RequiredResult", @@ -2245,40 +2332,13 @@ "gitgalaxy": 1031, "tree_sitter": null } - }, - { - "file_path": "godot/variant.h", - "name": "~Variant", - "readings": { - "ctags": 873, - "gitgalaxy": 873, - "tree_sitter": null - } - }, - { - "file_path": "godot/variant.h", - "name": "~PackedArrayRefBase", - "readings": { - "ctags": 217, - "gitgalaxy": 217, - "tree_sitter": null - } - }, - { - "file_path": "godot/variant.h", - "name": "operator T", - "readings": { - "ctags": 477, - "gitgalaxy": 476, - "tree_sitter": null - } } ], "metric": "existence", - "status": "unvalidated", + "status": "validated", "still_reproduces": true, "symbol_type": "function", - "verdict": null + "verdict": "Confirmed real tree-sitter-cpp grammar limitation, not a GitGalaxy or ctags defect. Every sampled case (GDScriptFunction::call, Main::setup, Main::setup2, Main::start, Object::Connection::operator Variant) is a large, complex function -- GDScriptFunction::call in particular (godot/gdscript_vm.cpp:499) is a bytecode interpreter's main dispatch loop using GNU 'labels as values' computed-goto syntax (`&&OPCODE_LABEL`) via the same OPCODES_TABLE/OPCODE macro family documented in the sibling agree[gitgalaxy,tree_sitter]_vs[ctags] entry -- a non-standard GNU extension tree-sitter-cpp's grammar does not support, which plausibly causes a parse error cascade that loses the enclosing function_definition node entirely rather than just misreading the body. ctags and GitGalaxy both correctly find and name these functions regardless of body content, since neither one needs to fully parse the function body to recognize its signature. tree-sitter's non-detection is a confirmed limitation in tree-sitter itself -- but no credit_tools adjustment applies: ctags and GitGalaxy are already a 2-of-3 AGREEING PAIR on this shape (agreeing_tools has 2 members), which already satisfies reconcile_symbols' own `len(present) >= 2` precision-credit condition naturally with no ledger adjustment needed. credit_tools exists for a LONE, single-tool claim (agreeing_tools with exactly 1 member) the base algorithm can't otherwise corroborate -- applying it to an already-mutually-corroborating pair would double-count (confirmed: this exact mistake briefly pushed ctags' precision past 100% before being caught and reverted in this same session)." }, "cpp/function/existence/agree[ctags,tree_sitter]_vs[gitgalaxy]": { "agreeing_tools": [ @@ -2291,10 +2351,10 @@ "gitgalaxy" ], "first_seen_at": "2026-08-18T22:44:22Z", - "investigated_at": null, - "investigated_by": null, + "investigated_at": "2026-08-21T00:00:00Z", + "investigated_by": "Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep", "language": "cpp", - "last_reconciled_at": "2026-08-21T11:59:54Z", + "last_reconciled_at": "2026-08-21T13:27:34Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -2308,10 +2368,10 @@ } ], "metric": "existence", - "status": "unvalidated", + "status": "validated", "still_reproduces": true, "symbol_type": "function", - "verdict": null + "verdict": "The single sampled occurrence (mlir/flatbuffer_export.cc:654, the `Translator` class's constructor) is exactly the bug filed as https://github.com/squid-protocol/gitgalaxy/issues/2009 -- a member-initializer-list spanning 906 characters exceeds GitGalaxy's func_start regex's 500-character cap for that clause, so the whole constructor is invisible to GitGalaxy despite ctags and tree-sitter both finding it correctly. GitGalaxy's non-detection is a confirmed, filed limitation -- but no credit_tools adjustment applies: ctags and tree-sitter are already a 2-of-3 AGREEING PAIR on this shape, which already satisfies reconcile_symbols' own `len(present) >= 2` precision-credit condition naturally. See the sibling agree[ctags,gitgalaxy]_vs[tree_sitter] entry for the full explanation of why credit_tools only applies to a LONE, single-tool claim, never an already-agreeing pair." }, "cpp/function/existence/agree[ctags]_vs[gitgalaxy,tree_sitter]": { "agreeing_tools": [ @@ -2324,108 +2384,108 @@ "tree_sitter" ], "first_seen_at": "2026-08-18T22:44:22Z", - "investigated_at": null, - "investigated_by": null, + "investigated_at": "2026-08-21T00:00:00Z", + "investigated_by": "Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep", "language": "cpp", - "last_reconciled_at": "2026-08-21T11:59:54Z", - "last_seen_count": 1074, + "last_reconciled_at": "2026-08-21T13:27:34Z", + "last_seen_count": 30, "last_seen_examples": [ { - "file_path": "NVDA/storage.cpp", - "name": "VBufStorage_buffer_t", + "file_path": "godot/object.h", + "name": "_get_bind_compatibility_methods", "readings": { - "ctags": 539, + "ctags": 552, "gitgalaxy": null, "tree_sitter": null } }, { - "file_path": "NVDA/storage.cpp", - "name": "VBufStorage_controlFieldNodeIdentifier_t", + "file_path": "godot/object.h", + "name": "_get_bind_methods", "readings": { - "ctags": 36, + "ctags": 549, "gitgalaxy": null, "tree_sitter": null } }, { - "file_path": "NVDA/storage.cpp", - "name": "VBufStorage_controlFieldNode_t", + "file_path": "godot/object.h", + "name": "_get_get", "readings": { - "ctags": 373, + "ctags": 555, "gitgalaxy": null, "tree_sitter": null } }, { - "file_path": "NVDA/storage.cpp", - "name": "VBufStorage_fieldNode_t", + "file_path": "godot/object.h", + "name": "_get_get_property_list", "readings": { - "ctags": 313, + "ctags": 561, "gitgalaxy": null, "tree_sitter": null } }, { - "file_path": "NVDA/storage.cpp", - "name": "VBufStorage_textFieldNode_t", + "file_path": "godot/object.h", + "name": "_get_notification", "readings": { - "ctags": 425, + "ctags": 573, "gitgalaxy": null, "tree_sitter": null } }, { - "file_path": "NVDA/storage.cpp", - "name": "addAttribute", + "file_path": "godot/object.h", + "name": "_get_property_can_revert", "readings": { - "ctags": 321, + "ctags": 567, "gitgalaxy": null, "tree_sitter": null } }, { - "file_path": "NVDA/storage.cpp", - "name": "addControlFieldNode", + "file_path": "godot/object.h", + "name": "_get_property_get_revert", "readings": { - "ctags": 548, + "ctags": 570, "gitgalaxy": null, "tree_sitter": null } }, { - "file_path": "NVDA/storage.cpp", - "name": "addControlFieldNode", + "file_path": "godot/object.h", + "name": "_get_set", "readings": { - "ctags": 561, + "ctags": 558, "gitgalaxy": null, "tree_sitter": null } }, { - "file_path": "NVDA/storage.cpp", - "name": "addReferenceNodeToBuffer", + "file_path": "godot/object.h", + "name": "_get_validate_property", "readings": { - "ctags": 1231, + "ctags": 564, "gitgalaxy": null, "tree_sitter": null } }, { - "file_path": "NVDA/storage.cpp", - "name": "addTextFieldNode", + "file_path": "godot/object.h", + "name": "operator Ref", "readings": { - "ctags": 585, + "ctags": 1036, "gitgalaxy": null, "tree_sitter": null } } ], "metric": "existence", - "status": "unvalidated", + "status": "validated", "still_reproduces": true, "symbol_type": "function", - "verdict": null + "verdict": "Confirmed ctags-only limitation: ctags parses INSIDE C++ macro DEFINITION bodies as if they were real, already-expanded code. godot/object.h's GDCLASS/_FORCE_INLINE_-based macros (`#define GDCLASS(m_class, m_inherits) ... _FORCE_INLINE_ bool (Object::*_get_get() const)(...) {...} ...`) never run as written -- they only produce real code once expanded at a `GDCLASS(SomeClass, Base)` call site elsewhere -- but ctags tags `_get_get`/`_get_set`/`_get_bind_methods`/`_get_bind_compatibility_methods`/`_get_notification`/`_get_property_can_revert`/`_get_property_get_revert`/`_get_validate_property`/`_get_get_property_list` (all 9 sampled cases, all from this same macro) as if they were ordinary member functions. Neither GitGalaxy nor tree-sitter are fooled by this. Documented in ctags_reader.py's KIND MAPS section (cpp bullet) rather than fixed -- this is ctags' own parser behavior, nothing in this repo's tooling can distinguish a macro-definition body from real code without reimplementing preprocessing." }, "cpp/function/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]": { "agreeing_tools": [ @@ -2433,113 +2493,116 @@ "tree_sitter" ], "credit_tools": [], - "debit_tools": [], + "debit_tools": [ + "gitgalaxy", + "tree_sitter" + ], "dissenting_tools": [ "ctags" ], "first_seen_at": "2026-08-18T22:44:22Z", - "investigated_at": null, - "investigated_by": null, + "investigated_at": "2026-08-21T00:00:00Z", + "investigated_by": "Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep", "language": "cpp", - "last_reconciled_at": "2026-08-21T11:59:54Z", - "last_seen_count": 1097, + "last_reconciled_at": "2026-08-21T13:27:34Z", + "last_seen_count": 105, "last_seen_examples": [ { - "file_path": "NVDA/storage.cpp", - "name": "VBufStorage_buffer_t::getLineOffsets", + "file_path": "godot/gdscript_vm.cpp", + "name": "OPCODE", "readings": { "ctags": null, - "gitgalaxy": 1066, - "tree_sitter": 1066 + "gitgalaxy": 761, + "tree_sitter": 761 } }, { - "file_path": "NVDA/storage.cpp", - "name": "VBufStorage_buffer_t::findNodeByAttributes", + "file_path": "godot/gdscript_vm.cpp", + "name": "OPCODE", "readings": { "ctags": null, - "gitgalaxy": 973, - "tree_sitter": 973 + "gitgalaxy": 848, + "tree_sitter": 848 } }, { - "file_path": "NVDA/storage.cpp", - "name": "VBufStorage_fieldNode_t::nextNodeInTree", + "file_path": "godot/gdscript_vm.cpp", + "name": "OPCODE", "readings": { "ctags": null, - "gitgalaxy": 57, - "tree_sitter": 57 + "gitgalaxy": 865, + "tree_sitter": 865 } }, { - "file_path": "NVDA/storage.cpp", - "name": "VBufStorage_buffer_t::insertNode", + "file_path": "godot/gdscript_vm.cpp", + "name": "OPCODE", "readings": { "ctags": null, - "gitgalaxy": 445, - "tree_sitter": 445 + "gitgalaxy": 879, + "tree_sitter": 879 } }, { - "file_path": "NVDA/storage.cpp", - "name": "VBufStorage_buffer_t::unlinkFieldNode", + "file_path": "godot/gdscript_vm.cpp", + "name": "OPCODE", "readings": { "ctags": null, - "gitgalaxy": 766, - "tree_sitter": 766 + "gitgalaxy": 902, + "tree_sitter": 902 } }, { - "file_path": "NVDA/storage.cpp", - "name": "VBufStorage_buffer_t::replaceSubtrees", + "file_path": "godot/gdscript_vm.cpp", + "name": "OPCODE", "readings": { "ctags": null, - "gitgalaxy": 642, - "tree_sitter": 642 + "gitgalaxy": 932, + "tree_sitter": 932 } }, { - "file_path": "NVDA/storage.cpp", - "name": "VBufStorage_fieldNode_t::getTextInRange", + "file_path": "godot/gdscript_vm.cpp", + "name": "OPCODE", "readings": { "ctags": null, - "gitgalaxy": 274, - "tree_sitter": 274 + "gitgalaxy": 954, + "tree_sitter": 954 } }, { - "file_path": "NVDA/storage.cpp", - "name": "VBufStorage_buffer_t::addTextFieldNode", + "file_path": "godot/gdscript_vm.cpp", + "name": "OPCODE", "readings": { "ctags": null, - "gitgalaxy": 585, - "tree_sitter": 585 + "gitgalaxy": 988, + "tree_sitter": 988 } }, { - "file_path": "NVDA/storage.cpp", - "name": "VBufStorage_buffer_t::addTextFieldNode", + "file_path": "godot/gdscript_vm.cpp", + "name": "OPCODE", "readings": { "ctags": null, - "gitgalaxy": 623, - "tree_sitter": 623 + "gitgalaxy": 1034, + "tree_sitter": 1034 } }, { - "file_path": "NVDA/storage.cpp", - "name": "VBufStorage_fieldNode_t::generateAttributesForMarkupOpeningTag", + "file_path": "godot/gdscript_vm.cpp", + "name": "OPCODE", "readings": { "ctags": null, - "gitgalaxy": 225, - "tree_sitter": 225 + "gitgalaxy": 1068, + "tree_sitter": 1068 } } ], "metric": "existence", - "status": "unvalidated", + "status": "validated", "still_reproduces": true, "symbol_type": "function", - "verdict": null + "verdict": "Two distinct causes, both confirmed via direct source reading. (1) The overwhelming majority of this shape (confirmed on samples spanning NVDA/storage.cpp, godot/*, mlir/flatbuffer_export.cc) was a bug in THIS repo's own ctags_reader.py: ctags reports an out-of-class method's bare, unqualified name (`getLineOffsets`) plus a separate scope field, while GitGalaxy/tree-sitter both read the fully-qualified identifier straight from source text (`VBufStorage_buffer_t::getLineOffsets`) -- the two never matched by name. Fixed in this session (`_QUALIFY_NAME_WITH_SCOPE`, `_cpp_qualified_name_candidates`, `--pattern-length-limit=0`, all in ctags_reader.py) by re-joining name+scope from ctags' own tag data, gated on the literal qualified text actually appearing in the tag's verbatim source line so an ordinary in-class-body method (never qualified in source) isn't wrongly qualified too. This alone resolved ~1000 of the original 1097 occurrences. (2) The remainder (105 after the fix, dominated 10/10 sampled by the literal name `OPCODE`) is a genuine, different cause: godot/gdscript_vm.cpp's bytecode interpreter uses `#define OPCODE(m_op) case m_op:` -- a macro invocation used as a switch-case label, not a function call. Both GitGalaxy's func_start regex AND tree-sitter's cpp grammar independently misparse the repeated `OPCODE(OP_X) { ... }` shape as if it were a function definition named `OPCODE`; ctags correctly does not. This is a genuine shared mistake, not real corroboration." }, "cpp/function/existence/agree[gitgalaxy]_vs[ctags,tree_sitter]": { "agreeing_tools": [ @@ -2552,21 +2615,12 @@ "tree_sitter" ], "first_seen_at": "2026-08-18T22:44:22Z", - "investigated_at": null, - "investigated_by": null, + "investigated_at": "2026-08-21T00:00:00Z", + "investigated_by": "Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep", "language": "cpp", - "last_reconciled_at": "2026-08-21T11:59:54Z", - "last_seen_count": 62, + "last_reconciled_at": "2026-08-21T13:27:34Z", + "last_seen_count": 10, "last_seen_examples": [ - { - "file_path": "godot/gdscript_vm.cpp", - "name": "GDScriptFunction::call", - "readings": { - "ctags": null, - "gitgalaxy": 499, - "tree_sitter": null - } - }, { "file_path": "godot/gdscript_vm.cpp", "name": "OPCODE_WHILE", @@ -2604,56 +2658,65 @@ } }, { - "file_path": "godot/main.cpp", - "name": "Main::setup", + "file_path": "godot/variant.cpp", + "name": "Variant::operator ::RID", "readings": { "ctags": null, - "gitgalaxy": 1027, + "gitgalaxy": 2002, "tree_sitter": null } }, { - "file_path": "godot/main.cpp", - "name": "Main::setup2", + "file_path": "godot/variant.cpp", + "name": "Variant::operator ::AABB", "readings": { "ctags": null, - "gitgalaxy": 3007, + "gitgalaxy": 1882, "tree_sitter": null } }, { - "file_path": "godot/main.cpp", - "name": "Main::start", + "file_path": "godot/variant.cpp", + "name": "Variant::operator Object *", "readings": { "ctags": null, - "gitgalaxy": 3987, + "gitgalaxy": 2024, "tree_sitter": null } }, { - "file_path": "godot/object.cpp", - "name": "Object::Connection::operator Variant", + "file_path": "mlir/flatbuffer_export.cc", + "name": "attribute_buffer_applier_factories_", "readings": { "ctags": null, - "gitgalaxy": 108, + "gitgalaxy": 679, "tree_sitter": null } }, { - "file_path": "godot/variant.cpp", - "name": "Variant::operator Vector4i", + "file_path": "powertoys/FancyZones.cpp", + "name": "m_draggingState", + "readings": { + "ctags": null, + "gitgalaxy": 75, + "tree_sitter": null + } + }, + { + "file_path": "powertoys/main.cpp", + "name": "std::thread", "readings": { "ctags": null, - "gitgalaxy": 1855, + "gitgalaxy": 88, "tree_sitter": null } } ], "metric": "existence", - "status": "unvalidated", + "status": "validated", "still_reproduces": true, "symbol_type": "function", - "verdict": null + "verdict": "Compound shape, three distinct causes confirmed via source, not one. (1) Most of the sample (OPCODE_WHILE x2, OPCODE_SWITCH, OPCODE) is the same GG+tree-sitter shared macro-misparse family documented in the sibling agree[gitgalaxy,tree_sitter]_vs[ctags] entry (godot/gdscript_vm.cpp's OPCODE/OPCODE_WHILE/OPCODE_SWITCH dispatch macros) -- here landing as 'GitGalaxy alone' because tree-sitter's own error recovery on this repeated macro pattern isn't fully deterministic across every occurrence, not because the underlying cause differs. GitGalaxy is WRONG for this portion (same debit as the sibling entry, not double-counted here since debit_tools is per-shape). (2) `attribute_buffer_applier_factories_`/`m_draggingState`/`std::thread` are a separate, real GitGalaxy FALSE POSITIVE: a lambda passed as a constructor argument or member-initializer-list entry (`m_draggingState([this]() {...}),`, `std::thread([...]() {...}).detach();`) is misread as a function definition. Filed as https://github.com/squid-protocol/gitgalaxy/issues/2013 . (3) `Variant::operator ::RID`/`Variant::operator ::AABB`/`Variant::operator Object *` are real functions GitGalaxy correctly finds (confirmed via godot/variant.cpp source) that didn't rank-match ctags/tree-sitter's own readings of the same functions by exact name string -- a residual, low-priority naming-comparison edge case (global-scope `::`-prefixed conversion-operator return types) not chased further in this pass. No credit/debit applied given the mixed, three-cause nature of this shape." }, "cpp/function/existence/agree[tree_sitter]_vs[ctags,gitgalaxy]": { "agreeing_tools": [ @@ -2666,10 +2729,10 @@ "gitgalaxy" ], "first_seen_at": "2026-08-18T22:44:22Z", - "investigated_at": null, - "investigated_by": null, + "investigated_at": "2026-08-21T00:00:00Z", + "investigated_by": "Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep", "language": "cpp", - "last_reconciled_at": "2026-08-21T11:59:54Z", + "last_reconciled_at": "2026-08-21T13:27:34Z", "last_seen_count": 98, "last_seen_examples": [ { @@ -2764,10 +2827,10 @@ } ], "metric": "existence", - "status": "unvalidated", + "status": "validated", "still_reproduces": true, "symbol_type": "function", - "verdict": null + "verdict": "Confirmed real tree-sitter-side artifacts, mixed causes, not chased to a code fix in this pass (would need deeper grammar-level investigation than this sweep's budget). Sample breaks into: (1) bare control-flow keywords ('for' at godot/node.cpp:2518, 'if' at godot/object.cpp:784/827) reported as if they were function NAMES -- tree-sitter's own error-recovery misparsing a control-flow statement as a function_definition-shaped node somewhere nearby, the same general failure class already documented elsewhere in this codebase for other languages (e.g. javascript's #1633 Flow-typed misparse), just not previously confirmed for cpp; (2) 'void' as a function name (3 samples) -- likely the same error-recovery mechanism producing a different malformed node shape; (3) conversion-operator names carrying tree-sitter's own trailing return-type/const-suffix convention (`Object::Connection::operator Variant() const`, `operator=` samples) where GitGalaxy and ctags both agree on the bare form (`operator Variant`) without the suffix -- a tree-sitter-side node-name-construction convention difference (in `tsaa._get_node_name`), confirmed to affect ~56 occurrences corpus-wide during this sweep but not isolated to a specific code change given how heavily special-cased and widely shared that helper already is across many languages. No credit/debit applied -- tree-sitter is the one that's wrong here, alone, so there's no consensus for ctags/GitGalaxy to be credited toward (they already agree with each other and are excluded from this shape entirely)." }, "csharp/class/existence/agree[ctags,gitgalaxy]_vs[tree_sitter]": { "agreeing_tools": [ @@ -2783,8 +2846,8 @@ "investigated_at": null, "investigated_by": null, "language": "csharp", - "last_reconciled_at": "2026-08-21T12:00:00Z", - "last_seen_count": 3, + "last_reconciled_at": "2026-08-21T13:27:40Z", + "last_seen_count": 9, "last_seen_examples": [ { "file_path": "roslyn/LanguageParser.cs", @@ -2795,6 +2858,60 @@ "tree_sitter": null } }, + { + "file_path": "roslyn/LanguageParser.cs", + "name": "VariableFlags", + "readings": { + "ctags": 5379, + "gitgalaxy": null, + "tree_sitter": null + } + }, + { + "file_path": "roslyn/LanguageParser.cs", + "name": "NameOptions", + "readings": { + "ctags": 5997, + "gitgalaxy": null, + "tree_sitter": null + } + }, + { + "file_path": "roslyn/LanguageParser.cs", + "name": "ScanTypeArgumentListKind", + "readings": { + "ctags": 6228, + "gitgalaxy": null, + "tree_sitter": null + } + }, + { + "file_path": "roslyn/LanguageParser.cs", + "name": "ScanTypeFlags", + "readings": { + "ctags": 7115, + "gitgalaxy": null, + "tree_sitter": null + } + }, + { + "file_path": "roslyn/LanguageParser.cs", + "name": "ParseTypeMode", + "readings": { + "ctags": 7565, + "gitgalaxy": null, + "tree_sitter": null + } + }, + { + "file_path": "roslyn/LanguageParser.cs", + "name": "Precedence", + "readings": { + "ctags": 11187, + "gitgalaxy": null, + "tree_sitter": null + } + }, { "file_path": "roslyn/LanguageParser.cs", "name": "DisposableResetPoint", @@ -2834,7 +2951,7 @@ "investigated_at": null, "investigated_by": null, "language": "csharp", - "last_reconciled_at": "2026-08-21T12:00:00Z", + "last_reconciled_at": "2026-08-21T13:27:40Z", "last_seen_count": 5, "last_seen_examples": [ { @@ -2885,7 +3002,7 @@ ], "metric": "existence", "status": "unvalidated", - "still_reproduces": true, + "still_reproduces": false, "symbol_type": "class", "verdict": null }, @@ -2903,7 +3020,7 @@ "investigated_at": null, "investigated_by": null, "language": "csharp", - "last_reconciled_at": "2026-08-21T12:00:00Z", + "last_reconciled_at": "2026-08-21T13:27:40Z", "last_seen_count": 6, "last_seen_examples": [ { @@ -2963,7 +3080,7 @@ ], "metric": "existence", "status": "unvalidated", - "still_reproduces": true, + "still_reproduces": false, "symbol_type": "class", "verdict": null }, @@ -2981,7 +3098,7 @@ "investigated_at": null, "investigated_by": null, "language": "csharp", - "last_reconciled_at": "2026-08-21T12:00:00Z", + "last_reconciled_at": "2026-08-21T13:27:40Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -3014,7 +3131,7 @@ "investigated_at": null, "investigated_by": null, "language": "csharp", - "last_reconciled_at": "2026-08-21T12:00:00Z", + "last_reconciled_at": "2026-08-21T13:27:40Z", "last_seen_count": 7, "last_seen_examples": [ { @@ -3101,7 +3218,7 @@ "investigated_at": null, "investigated_by": null, "language": "csharp", - "last_reconciled_at": "2026-08-21T12:00:00Z", + "last_reconciled_at": "2026-08-21T13:27:40Z", "last_seen_count": 4, "last_seen_examples": [ { @@ -3160,7 +3277,7 @@ "investigated_at": null, "investigated_by": null, "language": "csharp", - "last_reconciled_at": "2026-08-21T12:00:00Z", + "last_reconciled_at": "2026-08-21T13:27:40Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -3193,7 +3310,7 @@ "investigated_at": null, "investigated_by": null, "language": "csharp", - "last_reconciled_at": "2026-08-21T12:00:00Z", + "last_reconciled_at": "2026-08-21T13:27:40Z", "last_seen_count": 271, "last_seen_examples": [ { @@ -3307,7 +3424,7 @@ "investigated_at": null, "investigated_by": null, "language": "csharp", - "last_reconciled_at": "2026-08-21T12:00:00Z", + "last_reconciled_at": "2026-08-21T13:27:40Z", "last_seen_count": 4, "last_seen_examples": [ { @@ -3367,7 +3484,7 @@ "investigated_at": null, "investigated_by": null, "language": "csharp", - "last_reconciled_at": "2026-08-21T12:00:00Z", + "last_reconciled_at": "2026-08-21T13:27:40Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -3400,7 +3517,7 @@ "investigated_at": null, "investigated_by": null, "language": "csharp", - "last_reconciled_at": "2026-08-21T12:00:00Z", + "last_reconciled_at": "2026-08-21T13:27:40Z", "last_seen_count": 107, "last_seen_examples": [ { @@ -3514,7 +3631,7 @@ "investigated_at": null, "investigated_by": null, "language": "csharp", - "last_reconciled_at": "2026-08-21T12:00:00Z", + "last_reconciled_at": "2026-08-21T13:27:40Z", "last_seen_count": 48, "last_seen_examples": [ { @@ -3628,7 +3745,7 @@ "investigated_at": null, "investigated_by": null, "language": "csharp", - "last_reconciled_at": "2026-08-21T12:00:00Z", + "last_reconciled_at": "2026-08-21T13:27:40Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -3661,7 +3778,7 @@ "investigated_at": null, "investigated_by": null, "language": "css", - "last_reconciled_at": "2026-08-21T12:00:02Z", + "last_reconciled_at": "2026-08-21T13:27:41Z", "last_seen_count": 3, "last_seen_examples": [ { @@ -3710,7 +3827,7 @@ "investigated_at": null, "investigated_by": null, "language": "dart", - "last_reconciled_at": "2026-08-21T12:00:06Z", + "last_reconciled_at": "2026-08-21T13:27:45Z", "last_seen_count": 216, "last_seen_examples": [ { @@ -3813,7 +3930,7 @@ "investigated_at": null, "investigated_by": null, "language": "dart", - "last_reconciled_at": "2026-08-21T12:00:06Z", + "last_reconciled_at": "2026-08-21T13:27:45Z", "last_seen_count": 37, "last_seen_examples": [ { @@ -3916,7 +4033,7 @@ "investigated_at": null, "investigated_by": null, "language": "dart", - "last_reconciled_at": "2026-08-21T12:00:06Z", + "last_reconciled_at": "2026-08-21T13:27:45Z", "last_seen_count": 18, "last_seen_examples": [ { @@ -4020,7 +4137,7 @@ "investigated_at": null, "investigated_by": null, "language": "fortran", - "last_reconciled_at": "2026-08-21T12:00:13Z", + "last_reconciled_at": "2026-08-21T13:27:51Z", "last_seen_count": 8, "last_seen_examples": [ { @@ -4115,7 +4232,7 @@ "investigated_at": "2026-08-21T00:00:00Z", "investigated_by": "Claude Sonnet 5, direct investigation (surfaced while re-blessing the tri-comparison chart after #1973/#1985)", "language": "fortran", - "last_reconciled_at": "2026-08-21T12:00:13Z", + "last_reconciled_at": "2026-08-21T13:27:51Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -4147,7 +4264,7 @@ "investigated_at": null, "investigated_by": null, "language": "fortran", - "last_reconciled_at": "2026-08-21T12:00:13Z", + "last_reconciled_at": "2026-08-21T13:27:51Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -4180,7 +4297,7 @@ "investigated_at": null, "investigated_by": null, "language": "fortran", - "last_reconciled_at": "2026-08-21T12:00:13Z", + "last_reconciled_at": "2026-08-21T13:27:51Z", "last_seen_count": 14, "last_seen_examples": [ { @@ -4294,7 +4411,7 @@ "investigated_at": null, "investigated_by": null, "language": "fortran", - "last_reconciled_at": "2026-08-21T12:00:13Z", + "last_reconciled_at": "2026-08-21T13:27:51Z", "last_seen_count": 2, "last_seen_examples": [ { @@ -4336,7 +4453,7 @@ "investigated_at": null, "investigated_by": null, "language": "fortran", - "last_reconciled_at": "2026-08-21T12:00:13Z", + "last_reconciled_at": "2026-08-21T13:27:51Z", "last_seen_count": 2, "last_seen_examples": [ { @@ -4378,7 +4495,7 @@ "investigated_at": null, "investigated_by": null, "language": "go", - "last_reconciled_at": "2026-08-21T12:00:15Z", + "last_reconciled_at": "2026-08-21T13:27:53Z", "last_seen_count": 75, "last_seen_examples": [ { @@ -4492,7 +4609,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Claude Sonnet 5 (session investigation)", "language": "haskell", - "last_reconciled_at": "2026-08-21T12:00:18Z", + "last_reconciled_at": "2026-08-21T13:27:56Z", "last_seen_count": 16, "last_seen_examples": [ { @@ -4604,7 +4721,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Claude Sonnet 5 (session investigation)", "language": "haskell", - "last_reconciled_at": "2026-08-21T12:00:18Z", + "last_reconciled_at": "2026-08-21T13:27:56Z", "last_seen_count": 9, "last_seen_examples": [ { @@ -4709,7 +4826,7 @@ "investigated_at": null, "investigated_by": null, "language": "haskell", - "last_reconciled_at": "2026-08-21T12:00:18Z", + "last_reconciled_at": "2026-08-21T13:27:56Z", "last_seen_count": 38, "last_seen_examples": [ { @@ -4823,7 +4940,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Claude Sonnet 5 (dispatched agent investigation)", "language": "haskell", - "last_reconciled_at": "2026-08-21T12:00:18Z", + "last_reconciled_at": "2026-08-21T13:27:56Z", "last_seen_count": 103, "last_seen_examples": [ { @@ -4937,7 +5054,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Claude Sonnet 5 (dispatched agent investigation)", "language": "haskell", - "last_reconciled_at": "2026-08-21T12:00:18Z", + "last_reconciled_at": "2026-08-21T13:27:56Z", "last_seen_count": 69, "last_seen_examples": [ { @@ -5051,7 +5168,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Claude Sonnet 5 (session investigation)", "language": "haskell", - "last_reconciled_at": "2026-08-21T12:00:18Z", + "last_reconciled_at": "2026-08-21T13:27:56Z", "last_seen_count": 2, "last_seen_examples": [ { @@ -5092,7 +5209,7 @@ "investigated_at": null, "investigated_by": null, "language": "haskell", - "last_reconciled_at": "2026-08-21T12:00:18Z", + "last_reconciled_at": "2026-08-21T13:27:56Z", "last_seen_count": 2, "last_seen_examples": [ { @@ -5132,7 +5249,7 @@ "investigated_at": null, "investigated_by": null, "language": "haskell", - "last_reconciled_at": "2026-08-21T12:00:18Z", + "last_reconciled_at": "2026-08-21T13:27:56Z", "last_seen_count": 91, "last_seen_examples": [ { @@ -5246,7 +5363,7 @@ "investigated_at": null, "investigated_by": null, "language": "java", - "last_reconciled_at": "2026-08-21T12:00:21Z", + "last_reconciled_at": "2026-08-21T13:27:59Z", "last_seen_count": 28, "last_seen_examples": [ { @@ -5360,7 +5477,7 @@ "investigated_at": null, "investigated_by": null, "language": "java", - "last_reconciled_at": "2026-08-21T12:00:21Z", + "last_reconciled_at": "2026-08-21T13:27:59Z", "last_seen_count": 12, "last_seen_examples": [ { @@ -5474,7 +5591,7 @@ "investigated_at": null, "investigated_by": null, "language": "java", - "last_reconciled_at": "2026-08-21T12:00:21Z", + "last_reconciled_at": "2026-08-21T13:27:59Z", "last_seen_count": 28, "last_seen_examples": [ { @@ -5587,7 +5704,7 @@ "investigated_at": null, "investigated_by": null, "language": "java", - "last_reconciled_at": "2026-08-21T12:00:21Z", + "last_reconciled_at": "2026-08-21T13:27:59Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -5620,7 +5737,7 @@ "investigated_at": null, "investigated_by": null, "language": "java", - "last_reconciled_at": "2026-08-21T12:00:21Z", + "last_reconciled_at": "2026-08-21T13:27:59Z", "last_seen_count": 3, "last_seen_examples": [ { @@ -5671,7 +5788,7 @@ "investigated_at": null, "investigated_by": null, "language": "java", - "last_reconciled_at": "2026-08-21T12:00:21Z", + "last_reconciled_at": "2026-08-21T13:27:59Z", "last_seen_count": 315, "last_seen_examples": [ { @@ -5785,7 +5902,7 @@ "investigated_at": null, "investigated_by": null, "language": "java", - "last_reconciled_at": "2026-08-21T12:00:21Z", + "last_reconciled_at": "2026-08-21T13:27:59Z", "last_seen_count": 3, "last_seen_examples": [ { @@ -5836,7 +5953,7 @@ "investigated_at": null, "investigated_by": null, "language": "javascript", - "last_reconciled_at": "2026-08-21T12:00:24Z", + "last_reconciled_at": "2026-08-21T13:28:01Z", "last_seen_count": 96, "last_seen_examples": [ { @@ -5950,7 +6067,7 @@ "investigated_at": null, "investigated_by": null, "language": "javascript", - "last_reconciled_at": "2026-08-21T12:00:24Z", + "last_reconciled_at": "2026-08-21T13:28:01Z", "last_seen_count": 7, "last_seen_examples": [ { @@ -6037,7 +6154,7 @@ "investigated_at": null, "investigated_by": null, "language": "javascript", - "last_reconciled_at": "2026-08-21T12:00:24Z", + "last_reconciled_at": "2026-08-21T13:28:01Z", "last_seen_count": 2, "last_seen_examples": [ { @@ -6079,7 +6196,7 @@ "investigated_at": null, "investigated_by": null, "language": "javascript", - "last_reconciled_at": "2026-08-21T12:00:24Z", + "last_reconciled_at": "2026-08-21T13:28:01Z", "last_seen_count": 11, "last_seen_examples": [ { @@ -6193,7 +6310,7 @@ "investigated_at": null, "investigated_by": null, "language": "javascript", - "last_reconciled_at": "2026-08-21T12:00:24Z", + "last_reconciled_at": "2026-08-21T13:28:01Z", "last_seen_count": 150, "last_seen_examples": [ { @@ -6307,7 +6424,7 @@ "investigated_at": null, "investigated_by": null, "language": "javascript", - "last_reconciled_at": "2026-08-21T12:00:24Z", + "last_reconciled_at": "2026-08-21T13:28:01Z", "last_seen_count": 266, "last_seen_examples": [ { @@ -6421,7 +6538,7 @@ "investigated_at": null, "investigated_by": null, "language": "javascript", - "last_reconciled_at": "2026-08-21T12:00:24Z", + "last_reconciled_at": "2026-08-21T13:28:01Z", "last_seen_count": 182, "last_seen_examples": [ { @@ -6535,7 +6652,7 @@ "investigated_at": null, "investigated_by": null, "language": "javascript", - "last_reconciled_at": "2026-08-21T12:00:24Z", + "last_reconciled_at": "2026-08-21T13:28:01Z", "last_seen_count": 104, "last_seen_examples": [ { @@ -6649,7 +6766,7 @@ "investigated_at": null, "investigated_by": null, "language": "kotlin", - "last_reconciled_at": "2026-08-21T12:00:27Z", + "last_reconciled_at": "2026-08-21T13:28:04Z", "last_seen_count": 3, "last_seen_examples": [ { @@ -6700,7 +6817,7 @@ "investigated_at": null, "investigated_by": null, "language": "kotlin", - "last_reconciled_at": "2026-08-21T12:00:27Z", + "last_reconciled_at": "2026-08-21T13:28:04Z", "last_seen_count": 15, "last_seen_examples": [ { @@ -6814,7 +6931,7 @@ "investigated_at": null, "investigated_by": null, "language": "kotlin", - "last_reconciled_at": "2026-08-21T12:00:27Z", + "last_reconciled_at": "2026-08-21T13:28:04Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -6846,7 +6963,7 @@ "investigated_at": "2026-08-20", "investigated_by": "claude-sonnet-5 (direct source read, no dispatch needed)", "language": "m4", - "last_reconciled_at": "2026-08-21T12:00:35Z", + "last_reconciled_at": "2026-08-21T13:28:10Z", "last_seen_count": 4, "last_seen_examples": [ { @@ -6901,7 +7018,7 @@ "investigated_at": "2026-08-20", "investigated_by": "gemini-3.1-pro-high (agy), dispatched via tri-comparison-ledger-sweep, reviewed by claude-sonnet-5", "language": "m4", - "last_reconciled_at": "2026-08-21T12:00:35Z", + "last_reconciled_at": "2026-08-21T13:28:10Z", "last_seen_count": 76, "last_seen_examples": [ { @@ -7004,7 +7121,7 @@ "investigated_at": "2026-08-20", "investigated_by": "claude-sonnet-5 (direct source read, no dispatch needed)", "language": "m4", - "last_reconciled_at": "2026-08-21T12:00:35Z", + "last_reconciled_at": "2026-08-21T13:28:10Z", "last_seen_count": 36, "last_seen_examples": [ { @@ -7108,7 +7225,7 @@ "investigated_at": null, "investigated_by": null, "language": "makefile", - "last_reconciled_at": "2026-08-21T12:00:36Z", + "last_reconciled_at": "2026-08-21T13:28:11Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -7139,7 +7256,7 @@ "investigated_at": null, "investigated_by": null, "language": "matlab", - "last_reconciled_at": "2026-08-21T12:00:38Z", + "last_reconciled_at": "2026-08-21T13:28:13Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -7172,7 +7289,7 @@ "investigated_at": null, "investigated_by": null, "language": "objective-c", - "last_reconciled_at": "2026-08-21T12:00:40Z", + "last_reconciled_at": "2026-08-21T13:28:14Z", "last_seen_count": 91, "last_seen_examples": [ { @@ -7286,7 +7403,7 @@ "investigated_at": null, "investigated_by": null, "language": "objective-c", - "last_reconciled_at": "2026-08-21T12:00:40Z", + "last_reconciled_at": "2026-08-21T13:28:14Z", "last_seen_count": 104, "last_seen_examples": [ { @@ -7400,7 +7517,7 @@ "investigated_at": null, "investigated_by": null, "language": "objective-c", - "last_reconciled_at": "2026-08-21T12:00:40Z", + "last_reconciled_at": "2026-08-21T13:28:14Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -7433,7 +7550,7 @@ "investigated_at": null, "investigated_by": null, "language": "objective-c", - "last_reconciled_at": "2026-08-21T12:00:40Z", + "last_reconciled_at": "2026-08-21T13:28:14Z", "last_seen_count": 2, "last_seen_examples": [ { @@ -7475,7 +7592,7 @@ "investigated_at": null, "investigated_by": null, "language": "perl", - "last_reconciled_at": "2026-08-21T12:00:46Z", + "last_reconciled_at": "2026-08-21T13:28:20Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -7508,7 +7625,7 @@ "investigated_at": null, "investigated_by": null, "language": "perl", - "last_reconciled_at": "2026-08-21T12:00:46Z", + "last_reconciled_at": "2026-08-21T13:28:20Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -7539,7 +7656,7 @@ "investigated_at": null, "investigated_by": null, "language": "perl", - "last_reconciled_at": "2026-08-21T12:00:46Z", + "last_reconciled_at": "2026-08-21T13:28:20Z", "last_seen_count": 64, "last_seen_examples": [ { @@ -7653,7 +7770,7 @@ "investigated_at": null, "investigated_by": null, "language": "perl", - "last_reconciled_at": "2026-08-21T12:00:46Z", + "last_reconciled_at": "2026-08-21T13:28:20Z", "last_seen_count": 7, "last_seen_examples": [ { @@ -7740,7 +7857,7 @@ "investigated_at": null, "investigated_by": null, "language": "perl", - "last_reconciled_at": "2026-08-21T12:00:46Z", + "last_reconciled_at": "2026-08-21T13:28:20Z", "last_seen_count": 7, "last_seen_examples": [ { @@ -7827,7 +7944,7 @@ "investigated_at": null, "investigated_by": null, "language": "perl", - "last_reconciled_at": "2026-08-21T12:00:46Z", + "last_reconciled_at": "2026-08-21T13:28:20Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -7860,7 +7977,7 @@ "investigated_at": null, "investigated_by": null, "language": "perl", - "last_reconciled_at": "2026-08-21T12:00:46Z", + "last_reconciled_at": "2026-08-21T13:28:20Z", "last_seen_count": 122, "last_seen_examples": [ { @@ -7974,7 +8091,7 @@ "investigated_at": null, "investigated_by": null, "language": "php", - "last_reconciled_at": "2026-08-21T12:00:53Z", + "last_reconciled_at": "2026-08-21T13:28:25Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -8007,7 +8124,7 @@ "investigated_at": null, "investigated_by": null, "language": "php", - "last_reconciled_at": "2026-08-21T12:00:53Z", + "last_reconciled_at": "2026-08-21T13:28:25Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -8040,7 +8157,7 @@ "investigated_at": null, "investigated_by": null, "language": "php", - "last_reconciled_at": "2026-08-21T12:00:53Z", + "last_reconciled_at": "2026-08-21T13:28:25Z", "last_seen_count": 68, "last_seen_examples": [ { @@ -8154,7 +8271,7 @@ "investigated_at": null, "investigated_by": null, "language": "powershell", - "last_reconciled_at": "2026-08-21T12:00:57Z", + "last_reconciled_at": "2026-08-21T13:28:27Z", "last_seen_count": 7, "last_seen_examples": [ { @@ -8239,7 +8356,7 @@ "investigated_at": null, "investigated_by": null, "language": "powershell", - "last_reconciled_at": "2026-08-21T12:00:57Z", + "last_reconciled_at": "2026-08-21T13:28:27Z", "last_seen_count": 5, "last_seen_examples": [ { @@ -8308,7 +8425,7 @@ "investigated_at": null, "investigated_by": null, "language": "powershell", - "last_reconciled_at": "2026-08-21T12:00:57Z", + "last_reconciled_at": "2026-08-21T13:28:27Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -8341,7 +8458,7 @@ "investigated_at": null, "investigated_by": null, "language": "powershell", - "last_reconciled_at": "2026-08-21T12:00:57Z", + "last_reconciled_at": "2026-08-21T13:28:27Z", "last_seen_count": 16, "last_seen_examples": [ { @@ -8455,7 +8572,7 @@ "investigated_at": "2026-08-21T03:23:52Z", "investigated_by": "claude sonnet 5, tri-comparison-ledger-sweep (direct investigation, no dispatch needed)", "language": "python", - "last_reconciled_at": "2026-08-21T12:01:08Z", + "last_reconciled_at": "2026-08-21T13:28:36Z", "last_seen_count": 4, "last_seen_examples": [ { @@ -8515,7 +8632,7 @@ "investigated_at": "2026-08-21T03:23:52Z", "investigated_by": "claude sonnet 5, tri-comparison-ledger-sweep (direct investigation, no dispatch needed)", "language": "python", - "last_reconciled_at": "2026-08-21T12:01:08Z", + "last_reconciled_at": "2026-08-21T13:28:36Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -8548,7 +8665,7 @@ "investigated_at": "2026-08-21T12:03:03Z", "investigated_by": "claude sonnet 5, tri-comparison-ledger-sweep (direct investigation, no dispatch needed)", "language": "python", - "last_reconciled_at": "2026-08-21T12:01:08Z", + "last_reconciled_at": "2026-08-21T13:28:36Z", "last_seen_count": 100, "last_seen_examples": [ { @@ -8664,7 +8781,7 @@ "investigated_at": "2026-08-21T12:03:03Z", "investigated_by": "claude sonnet 5, tri-comparison-ledger-sweep (direct investigation, no dispatch needed)", "language": "python", - "last_reconciled_at": "2026-08-21T12:01:08Z", + "last_reconciled_at": "2026-08-21T13:28:36Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -8697,7 +8814,7 @@ "investigated_at": null, "investigated_by": null, "language": "ruby", - "last_reconciled_at": "2026-08-21T12:01:10Z", + "last_reconciled_at": "2026-08-21T13:28:37Z", "last_seen_count": 2, "last_seen_examples": [ { @@ -8739,7 +8856,7 @@ "investigated_at": null, "investigated_by": null, "language": "ruby", - "last_reconciled_at": "2026-08-21T12:01:10Z", + "last_reconciled_at": "2026-08-21T13:28:37Z", "last_seen_count": 6, "last_seen_examples": [ { @@ -8817,7 +8934,7 @@ "investigated_at": null, "investigated_by": null, "language": "ruby", - "last_reconciled_at": "2026-08-21T12:01:10Z", + "last_reconciled_at": "2026-08-21T13:28:37Z", "last_seen_count": 3, "last_seen_examples": [ { @@ -8868,7 +8985,7 @@ "investigated_at": null, "investigated_by": null, "language": "ruby", - "last_reconciled_at": "2026-08-21T12:01:10Z", + "last_reconciled_at": "2026-08-21T13:28:37Z", "last_seen_count": 6, "last_seen_examples": [ { @@ -8945,7 +9062,7 @@ "investigated_at": null, "investigated_by": null, "language": "rust", - "last_reconciled_at": "2026-08-21T12:01:14Z", + "last_reconciled_at": "2026-08-21T13:28:41Z", "last_seen_count": 14, "last_seen_examples": [ { @@ -9059,7 +9176,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Claude Sonnet 5 (resolved directly via live ctags run, no dispatch)", "language": "rust", - "last_reconciled_at": "2026-08-21T12:01:14Z", + "last_reconciled_at": "2026-08-21T13:28:41Z", "last_seen_count": 3, "last_seen_examples": [ { @@ -9112,7 +9229,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Gemini (dispatched via tri-comparison-ledger-sweep), confirmed by Claude Sonnet 5", "language": "rust", - "last_reconciled_at": "2026-08-21T12:01:14Z", + "last_reconciled_at": "2026-08-21T13:28:41Z", "last_seen_count": 25, "last_seen_examples": [ { @@ -9225,7 +9342,7 @@ "investigated_at": null, "investigated_by": null, "language": "rust", - "last_reconciled_at": "2026-08-21T12:01:14Z", + "last_reconciled_at": "2026-08-21T13:28:41Z", "last_seen_count": 3, "last_seen_examples": [ { @@ -9276,7 +9393,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Gemini (dispatched via tri-comparison-ledger-sweep, 2 rounds with self-correction), confirmed by Claude Sonnet 5", "language": "rust", - "last_reconciled_at": "2026-08-21T12:01:14Z", + "last_reconciled_at": "2026-08-21T13:28:41Z", "last_seen_count": 21, "last_seen_examples": [ { @@ -9388,7 +9505,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Gemini (dispatched via tri-comparison-ledger-sweep), confirmed by Claude Sonnet 5", "language": "rust", - "last_reconciled_at": "2026-08-21T12:01:14Z", + "last_reconciled_at": "2026-08-21T13:28:41Z", "last_seen_count": 21, "last_seen_examples": [ { @@ -9501,7 +9618,7 @@ "investigated_at": null, "investigated_by": null, "language": "rust", - "last_reconciled_at": "2026-08-21T12:01:14Z", + "last_reconciled_at": "2026-08-21T13:28:41Z", "last_seen_count": 83, "last_seen_examples": [ { @@ -9614,7 +9731,7 @@ "investigated_at": null, "investigated_by": null, "language": "rust", - "last_reconciled_at": "2026-08-21T12:01:14Z", + "last_reconciled_at": "2026-08-21T13:28:41Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -9647,7 +9764,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Claude Sonnet 5 (resolved directly via live ctags run, no dispatch)", "language": "rust", - "last_reconciled_at": "2026-08-21T12:01:14Z", + "last_reconciled_at": "2026-08-21T13:28:41Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -9682,7 +9799,7 @@ "investigated_at": "2026-08-19T00:00:00Z", "investigated_by": "Claude Sonnet 5 (resolved from existing Claim 6 documentation, no dispatch)", "language": "rust", - "last_reconciled_at": "2026-08-21T12:01:14Z", + "last_reconciled_at": "2026-08-21T13:28:41Z", "last_seen_count": 152, "last_seen_examples": [ { @@ -9794,7 +9911,7 @@ "investigated_at": null, "investigated_by": null, "language": "scala", - "last_reconciled_at": "2026-08-21T12:01:17Z", + "last_reconciled_at": "2026-08-21T13:28:43Z", "last_seen_count": 16, "last_seen_examples": [ { @@ -9897,7 +10014,7 @@ "investigated_at": "2026-08-20", "investigated_by": "gemini-3.1-pro-high (agy), dispatched via tri-comparison-ledger-sweep, reviewed and fixed by claude-sonnet-5", "language": "scheme", - "last_reconciled_at": "2026-08-21T12:01:21Z", + "last_reconciled_at": "2026-08-21T13:28:48Z", "last_seen_count": 84, "last_seen_examples": [ { @@ -9999,7 +10116,7 @@ "investigated_at": null, "investigated_by": null, "language": "scheme", - "last_reconciled_at": "2026-08-21T12:01:21Z", + "last_reconciled_at": "2026-08-21T13:28:48Z", "last_seen_count": 50, "last_seen_examples": [ { @@ -10103,7 +10220,7 @@ "investigated_at": null, "investigated_by": null, "language": "shell", - "last_reconciled_at": "2026-08-21T12:01:23Z", + "last_reconciled_at": "2026-08-21T13:28:49Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -10135,7 +10252,7 @@ "investigated_at": null, "investigated_by": null, "language": "solidity", - "last_reconciled_at": "2026-08-21T12:01:24Z", + "last_reconciled_at": "2026-08-21T13:28:50Z", "last_seen_count": 6, "last_seen_examples": [ { @@ -10205,7 +10322,7 @@ "investigated_at": null, "investigated_by": null, "language": "swift", - "last_reconciled_at": "2026-08-21T12:01:26Z", + "last_reconciled_at": "2026-08-21T13:28:52Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -10236,7 +10353,7 @@ "investigated_at": null, "investigated_by": null, "language": "swift", - "last_reconciled_at": "2026-08-21T12:01:26Z", + "last_reconciled_at": "2026-08-21T13:28:52Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -10267,7 +10384,7 @@ "investigated_at": null, "investigated_by": null, "language": "swift", - "last_reconciled_at": "2026-08-21T12:01:26Z", + "last_reconciled_at": "2026-08-21T13:28:52Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -10299,7 +10416,7 @@ "investigated_at": null, "investigated_by": null, "language": "tcl", - "last_reconciled_at": "2026-08-21T12:01:28Z", + "last_reconciled_at": "2026-08-21T13:28:53Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -10332,7 +10449,7 @@ "investigated_at": null, "investigated_by": null, "language": "tcl", - "last_reconciled_at": "2026-08-21T12:01:28Z", + "last_reconciled_at": "2026-08-21T13:28:53Z", "last_seen_count": 2, "last_seen_examples": [ { @@ -10374,7 +10491,7 @@ "investigated_at": null, "investigated_by": null, "language": "tcl", - "last_reconciled_at": "2026-08-21T12:01:28Z", + "last_reconciled_at": "2026-08-21T13:28:53Z", "last_seen_count": 4, "last_seen_examples": [ { @@ -10434,7 +10551,7 @@ "investigated_at": null, "investigated_by": null, "language": "tcl", - "last_reconciled_at": "2026-08-21T12:01:28Z", + "last_reconciled_at": "2026-08-21T13:28:53Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -10466,7 +10583,7 @@ "investigated_at": null, "investigated_by": null, "language": "tcl", - "last_reconciled_at": "2026-08-21T12:01:28Z", + "last_reconciled_at": "2026-08-21T13:28:53Z", "last_seen_count": 2, "last_seen_examples": [ { @@ -10508,7 +10625,7 @@ "investigated_at": null, "investigated_by": null, "language": "typescript", - "last_reconciled_at": "2026-08-21T12:01:49Z", + "last_reconciled_at": "2026-08-21T13:29:14Z", "last_seen_count": 2, "last_seen_examples": [ { @@ -10550,7 +10667,7 @@ "investigated_at": null, "investigated_by": null, "language": "typescript", - "last_reconciled_at": "2026-08-21T12:01:49Z", + "last_reconciled_at": "2026-08-21T13:29:14Z", "last_seen_count": 501, "last_seen_examples": [ { @@ -10662,7 +10779,7 @@ "investigated_at": null, "investigated_by": null, "language": "typescript", - "last_reconciled_at": "2026-08-21T12:01:49Z", + "last_reconciled_at": "2026-08-21T13:29:14Z", "last_seen_count": 4, "last_seen_examples": [ { @@ -10721,7 +10838,7 @@ "investigated_at": null, "investigated_by": null, "language": "typescript", - "last_reconciled_at": "2026-08-21T12:01:49Z", + "last_reconciled_at": "2026-08-21T13:29:14Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -10754,7 +10871,7 @@ "investigated_at": null, "investigated_by": null, "language": "typescript", - "last_reconciled_at": "2026-08-21T12:01:49Z", + "last_reconciled_at": "2026-08-21T13:29:14Z", "last_seen_count": 9, "last_seen_examples": [ { @@ -10859,7 +10976,7 @@ "investigated_at": null, "investigated_by": null, "language": "typescript", - "last_reconciled_at": "2026-08-21T12:01:49Z", + "last_reconciled_at": "2026-08-21T13:29:14Z", "last_seen_count": 61, "last_seen_examples": [ { @@ -10973,7 +11090,7 @@ "investigated_at": null, "investigated_by": null, "language": "typescript", - "last_reconciled_at": "2026-08-21T12:01:49Z", + "last_reconciled_at": "2026-08-21T13:29:14Z", "last_seen_count": 1907, "last_seen_examples": [ { @@ -11087,7 +11204,7 @@ "investigated_at": null, "investigated_by": null, "language": "typescript", - "last_reconciled_at": "2026-08-21T12:01:49Z", + "last_reconciled_at": "2026-08-21T13:29:14Z", "last_seen_count": 2, "last_seen_examples": [ { @@ -11129,7 +11246,7 @@ "investigated_at": null, "investigated_by": null, "language": "typescript", - "last_reconciled_at": "2026-08-21T12:01:49Z", + "last_reconciled_at": "2026-08-21T13:29:14Z", "last_seen_count": 174, "last_seen_examples": [ { @@ -11242,7 +11359,7 @@ "investigated_at": null, "investigated_by": null, "language": "zig", - "last_reconciled_at": "2026-08-21T12:01:58Z", + "last_reconciled_at": "2026-08-21T13:29:22Z", "last_seen_count": 1, "last_seen_examples": [ { @@ -11273,7 +11390,7 @@ "investigated_at": null, "investigated_by": null, "language": "zig", - "last_reconciled_at": "2026-08-21T12:01:58Z", + "last_reconciled_at": "2026-08-21T13:29:22Z", "last_seen_count": 10, "last_seen_examples": [ { @@ -11376,7 +11493,7 @@ "investigated_at": null, "investigated_by": null, "language": "zig", - "last_reconciled_at": "2026-08-21T12:01:58Z", + "last_reconciled_at": "2026-08-21T13:29:22Z", "last_seen_count": 1, "last_seen_examples": [ { diff --git a/docs/self_scan/tri_comparison_points_of_interest.md b/docs/self_scan/tri_comparison_points_of_interest.md index 1cd143c7..c88be9f3 100644 --- a/docs/self_scan/tri_comparison_points_of_interest.md +++ b/docs/self_scan/tri_comparison_points_of_interest.md @@ -8,7 +8,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `agc_assembly` function existence: ctags agree, GitGalaxy differ -*2-vs-1 -- 215 occurrences as of 2026-08-21T11:59:36Z* +*2-vs-1 -- 215 occurrences as of 2026-08-21T13:27:16Z* **Verdict** (by Claude (Sonnet 5), direct investigation via tri-comparison-ledger-sweep, 2026-08-20T00:00:00Z): > Mixed-cause shape, fully accounted for via a corpus-wide cross-reference of ctags' actual output against GitGalaxy's raw func_start regex matches and its real pipeline/DB output (215 + 50 = 265, no unexplained residual). (1) 215/265 (81%): ctags' Asm "l" kind tags EVERY line-start label unconditionally, including pure data/constant-definition labels (e.g. ERASCON1 OCTAL 00061, S10BITS, LSTBNKCH -- AGC_BLOCK_TWO_SELF-CHECK.agc:133 and nearby) that are never followed by an executable instruction. GitGalaxy's func_start regex deliberately requires the label be followed by a real instruction mnemonic from a fixed whitelist, so it does not count these as functions -- a genuine, intentional precision distinction (code label vs. data label), not a GitGalaxy defect; ctags' generic Asm parser has no way to make this distinction at all. (2) 50/265 (19%): a real, confirmed GitGalaxy engine defect in detector.py's _slice_by_labels (Mode A), independently root-caused to two separate bugs: (a) `RELINT` is incorrectly included in `self.assembly_returns`'s early-termination keyword list (detector.py:572-575) -- in real AGC assembly RELINT means "release interrupt inhibit" and commonly opens a long interrupt-handler routine rather than closing one, so it truncates the real body to one line (confirmed: ELOOPFIN, AGC_BLOCK_TWO_SELF-CHECK.agc:303, a 20+-line real routine collapsed to just its own label line); (b) the `len(block.splitlines()) < 2` guard (detector.py:1973) unconditionally discards legitimate single-instruction assembly subroutines when the next func_start match sits on the very next line (confirmed: SOPTION1-SOPTION5+, AGC_BLOCK_TWO_SELF-CHECK.agc:210-214, each a real one-instruction label). Filed as #1949 -- a follow-up read-only Gemini/agy dispatch confirmed both root causes generalize beyond agc_assembly to the shared Mode A mechanism (assembly, cobol, fortran, abap all independently exhibit bug 1; assembly and cobol also exhibit bug 2), plus two further bug-1 variants not visible from agc_assembly alone: the terminator regex also false-matches inside comments (assembly) and inside hyphenated identifier names (cobol), not just legitimate-but-misclassified instructions. See #1949 for the full cross-language evidence and fix scope. No credit/debit -- the 215 portion is an honest scope difference (not two tools independently wrong about the same fact), and the 50 portion is GitGalaxy's own unresolved bug, not something ctags corroborates or contradicts. @@ -28,7 +28,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `agc_assembly` function existence: GitGalaxy agree, ctags differ -*2-vs-1 -- 37 occurrences as of 2026-08-21T11:59:36Z* +*2-vs-1 -- 37 occurrences as of 2026-08-21T13:27:16Z* **Verdict** (by Claude (Sonnet 5), direct investigation via tri-comparison-ledger-sweep, 2026-08-20T00:00:00Z): > Confirmed: all 35 occurrences are real AGC labels that GitGalaxy correctly extracts and Universal Ctags' generic Asm parser structurally cannot tag, due to AGC assembly's non-standard label-naming conventions. Two sub-patterns, both confirmed corpus-wide (14/35 + 21/35 = 35/35, not just the sample): (1) labels with an embedded hyphen -- AGC's own convention of naming a point relative to an event, e.g. TIG-35/TIG-30/CALLT-35 in BURN_BABY_BURN--MASTER_IGNITION_ROUTINE.agc:250/292/222 ("35/30 seconds before Time of Ignition"); (2) labels starting with a digit or a leading minus sign, e.g. 1CHK/2EBANK/-1CHK in AGC_BLOCK_TWO_SELF-CHECK.agc:184 (real label text is "-1CHK"). Directly verified via `ctags --language-force=Asm --kinds-Asm=l` against the real corpus files: ctags emits zero tags for any of these names (confirmed by grepping its actual output for the exact names and their surrounding CHK-suffixed siblings, which ARE tagged when they don't start with a hyphen/digit) -- ctags' Asm parser requires a tag name to start with a letter and contain no hyphen, neither of which is a real constraint in AGC assembly's own label syntax. GitGalaxy's func_start regex ([A-Z0-9_-]+ at line start) has no such restriction. This is a confirmed, structural ctags/Asm-parser limitation, not corroboration of anything wrong on GitGalaxy's side -- logged to docs/why_gitgalaxy_beats_ast_here.md. @@ -50,7 +50,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `assembly` function existence: ctags agree, GitGalaxy differ -*2-vs-1 -- 26 occurrences as of 2026-08-21T11:59:39Z* +*2-vs-1 -- 26 occurrences as of 2026-08-21T13:27:19Z* **Verdict** (by Claude (Sonnet 5), direct investigation via tri-comparison-ledger-sweep, 2026-08-20T00:00:00Z): > Mixed shape, no clean credit/debit call. (1) A real, confirmed GitGalaxy defect: the same detector.py `_slice_by_labels` bug filed for agc_assembly as #1949 (RELINT-style early truncation and single-line/blank-collapsed body discard) independently confirmed live for generic assembly too -- `del_command:` (bootos/os.asm:269) sits immediately before the next label `os22:` with nothing between, collapsing to a one-line block and getting discarded; `C:`/`prtstr:` (hellosilicon/matrixmultneon.s:90,92) are each followed only by a data directive (`.fill`, `.asciz`) then a blank line before the next label, same one-line-after-strip() collapse. All three are real regex matches (confirmed via direct func_start.finditer against the raw text) that never reach the final function list -- tracked under #1949, not a new issue. (2) A correct-by-design GitGalaxy exclusion: `.Lenv0:`/`.Largv0:` (cosmopolitan/ape.S:1784-1785) start with the `.L` prefix func_start's own negative lookahead deliberately excludes (GCC's own convention for compiler-generated local/temporary labels) -- both are genuinely data labels (`.asciz` string constants) here, not real subroutines; ctags' generic Asm parser has no such convention-awareness and tags them anyway. (3) ctags itself over-tags some non-callable constructs GitGalaxy correctly excludes -- C-preprocessor `#define` macro constants (`GRUB_MAGIC`/`GRUB_EAX`/`GRUB_AOUT`/`GRUB_CHECKSUM`/`USE_SYMBOL_HACK`, cosmopolitan/ape.S:49,1679-1682) are not real assembly labels at all (no trailing `:`), but ctags' Asm parser tags them regardless. No credit/debit -- the shape mixes a real unresolved GitGalaxy recall gap (#1949) with cases where ctags is the one over-tagging, not a clean corroboration story either direction. @@ -70,7 +70,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `assembly` function existence: GitGalaxy agree, ctags differ -*2-vs-1 -- 7 occurrences as of 2026-08-21T11:59:39Z* +*2-vs-1 -- 7 occurrences as of 2026-08-21T13:27:19Z* **Verdict** (by Claude (Sonnet 5), direct investigation via tri-comparison-ledger-sweep, 2026-08-20T00:00:00Z): > Mixed shape, three distinct confirmed mechanisms, no clean credit/debit call (real wins and real gaps in both directions within the same shape). (1) A dot-prefix naming-convention split -- NASM/GAS local labels scoped to the preceding global label are written with a leading `.` (e.g. `.load_vec:`, `.loop:` in bootos/os.asm:197,306), which GitGalaxy's func_start regex captures verbatim but ctags' Asm parser strips before emitting the tag (confirmed: ctags reports the SAME real label as `load_vec`/`loop`, no dot -- both tools genuinely found the same real construct, they just serialize the name differently). This is a name-string artifact of exact-string ledger grouping, not a detection difference on either side. (2) A genuine ctags gap: purely numeric local labels (`.1:`, `.2:` in bootos/counter.asm:52,67) are not tagged by ctags' Asm parser under ANY name (confirmed: neither `1`/`2` nor `.1`/`.2` appear in its output at all) -- GitGalaxy correctly finds these. (3) A genuine GitGalaxy precision gap, the mirror image of agc_assembly's own win: unlike agc_assembly's func_start (which requires a label be followed by a real instruction opcode), generic assembly's func_start has no such requirement -- ANY `identifier:` at line start matches, so it also matches pure data/constant declaration labels ctags' comparatively more conservative reading skips: `max_entries: equ sector_size/entry_size` (bootos/os.asm:166, a compile-time constant, not a subroutine), and several string/metadata labels in cosmopolitan/ape.S followed only by `.asciz`/data directives (`ape.ident`, `freebsd.ident`, `netbsd.ident`, `openbsd.ident`, `str.error`, `str.crlf`, `str.e820`, `str.oldcpu`). Not filed as a bug -- generic assembly's func_start is intentionally permissive because it has to span wildly different, informally-specified dialects (x86/ARM/legacy real-mode) where a fixed per-opcode whitelist like agc_assembly's isn't practical; worth a future harden-language-extraction look at whether a narrower heuristic (e.g. excluding labels followed only by known data-directive pseudo-ops like .asciz/.long/.byte/equ) could recover some of this precision without losing real dialect coverage, but that's a design tradeoff, not a clear regression to fix urgently. @@ -89,7 +89,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `c` function existence: tree-sitter agree, GitGalaxy, ctags differ -*2-vs-1 -- 74 occurrences as of 2026-08-21T11:59:44Z* +*2-vs-1 -- 74 occurrences as of 2026-08-21T13:27:24Z* **Verdict** (by Gemini (dispatched via tri-comparison-ledger-sweep), confirmed by Claude Sonnet 5, 2026-08-19T00:00:00Z): > Confirmed, independently verified all 6 sampled names against real source -- GitGalaxy and ctags both correct, tree-sitter over-recalling from two related but distinct preprocessor-driven mechanisms, both already covered by existing infrastructure: (1) keyword/macro misparse -- 'if' (dictobject.c:522-527, an `#if SIZEOF_VOID_P > 4` / `else if` sequence desyncs the parse) and 'DICT___REVERSED___METHODDEF' (dictobject.c:5102, a PyMethodDef array-initializer macro, not a definition) are both ALREADY in tree_sitter_accuracy_audit.py's `_C_KNOWN_MACRO_HALLUCINATIONS` exclusion set (confirmed by reading it directly) -- this tri-comparison tool's raw walk deliberately doesn't apply that list (it's a curated, ground-truth-shaped judgment call, appropriately left to reconciliation per this module's own stated design, not baked into the walk). (2) dead #if 0 code -- '_PyObject_ManagedDictValidityCheck' (dictobject.c:7396) and 'tos_char'/'print_stack'/'print_stacks' (frameobject.c:1264-1313) are genuinely well-formed function definitions sitting entirely inside `#if 0 ... #endif` guards; tree-sitter has no preprocessor model and parses the dead branch as live code. Both mechanisms are already the exact shape docs/why_gitgalaxy_beats_ast_here.md's Claim 8 names generically ('a dead #if 0 block... macro definitions... that merely look structural') -- added these 4 new concrete citations to Claim 8's evidence section rather than treating this as a new finding. No GitHub issue -- both tools already behave as intended; this is expected, already-documented tree-sitter preprocessor-blindness surfacing under the new tri-comparison reconciliation, not a fresh defect. @@ -109,7 +109,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `c` function existence: GitGalaxy, ctags agree, tree-sitter differ -*2-vs-1 -- 13 occurrences as of 2026-08-21T11:59:44Z* +*2-vs-1 -- 13 occurrences as of 2026-08-21T13:27:24Z* **Verdict** (by Gemini (dispatched via tri-comparison-ledger-sweep), confirmed by Claude Sonnet 5, 2026-08-19T00:00:00Z): > 3 distinct causes, all genuine tree-sitter-c grammar limitations (GitGalaxy and ctags both correct in all 10 sampled cases) -- confirmed via dispatched investigation (which ran tree-sitter's C grammar directly and found ERROR nodes in every case) plus independent source-level spot-checks of all 3 trigger shapes. This is a C-scale instance of Claim 7 (CPP-directive-driven recall loss) -- added to that claim's evidence section. (1) 4 samples: an #if/#else pair splitting a single `if` condition inside a function body (ceval.c:33, _Py_ReachedRecursionLimitWithMargin). (2) 5 samples: bare, un-semicoloned macro invocations the grammar can't cleanly recover from, losing the next real function (object.c:1269-1271's _Py_COMP_DIAG_PUSH/IGNORE_DEPR_DECLS/POP before _PyObject_SetAttributeErrorContext; similar shape for the typeobject.c slot-getattr cluster). (3) 1 sample: #if/#endif wrapping only the `static` storage-class specifier, separated from the rest of the signature (micropython/compile.c:3473-3476, mp_compile_to_raw_code). Unlike Fortran's existing Claim 7 evidence (entire trailing sections lost), C's version is local -- one function lost per trigger, not a cascading region. No GitHub issue -- documented as new Claim 7 evidence, not a fixable tooling bug (this repo doesn't control tree-sitter-c's grammar). @@ -129,7 +129,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `c` function existence: ctags agree, GitGalaxy, tree-sitter differ -*2-vs-1 -- 7 occurrences as of 2026-08-21T11:59:44Z* +*2-vs-1 -- 7 occurrences as of 2026-08-21T13:27:24Z* **Verdict** (by Claude Sonnet 5 (resolved + fixed directly, no dispatch needed), 2026-08-19T00:00:00Z): > Confirmed real ctags limitation, not a GitGalaxy or tree-sitter defect -- resolved directly (no dispatch needed), source read confirms all 7 sampled names. RICHCMP_WRAPPER/SLOT0/SLOT1/SLOT1BINFULL are all-caps macro names; every occurrence is a MACRO INVOCATION (a call to a previously-#define'd boilerplate-generating macro), not a function definition -- confirmed at cpython/typeobject.c:10099 (`RICHCMP_WRAPPER(lt, Py_LT)`) and :10544 (`SLOT1(slot_mp_subscript, __getitem__, PyObject *)`), same shape as the multiple SLOT0/SLOT1 hits at different lines (each is a separate invocation of the same macro generating a different wrapper function). ctags' regex-based C parser tags the macro-invocation site itself as a function; GitGalaxy and tree-sitter both correctly don't. Deliberately NOT fixed with a curated name-exclusion list in the gatherer (unlike the sibling __anon* class shape, this would require hand-curating specific macro names -- the same ground-truth-judgment category tri_comparison_gatherer.py's own docstring reasons belongs in reconciliation, not the raw reader) -- documented in ctags_reader.py instead, alongside its existing per-language notes. @@ -146,7 +146,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `c` function existence: GitGalaxy agree, tree-sitter, ctags differ -*2-vs-1 -- 4 occurrences as of 2026-08-21T11:59:44Z* +*2-vs-1 -- 4 occurrences as of 2026-08-21T13:27:24Z* **Verdict** (by Claude Sonnet 5 (resolved directly, no dispatch needed), 2026-08-19T00:00:00Z): > Confirmed GitGalaxy correct, real finding -- a new, narrower instance of Claim 3 (parse-error cascade), added to docs/why_gitgalaxy_beats_ast_here.md. All 4 sampled names (slot_mp_ass_subscript:10544, slot_nb_inplace_power:10697, slot_tp_repr:10714, slot_tp_hash:10730, all cpython/typeobject.c) are ordinary, unremarkable function definitions -- nothing unusual individually -- but each sits directly after a bare SLOT0/SLOT1 macro-invocation LINE (`SLOT1(slot_mp_subscript, __getitem__, PyObject *)`, `SLOT0(slot_tp_str, __str__)`, etc.) that isn't valid freestanding C without macro expansion. GitGalaxy's regex has no adjacency sensitivity and finds all 4 correctly; both ctags and tree-sitter locally lose the SINGLE function immediately following each such line (recovers after just one function, not a full cascade to EOF -- confirmed by resolving all 4 as isolated single-function misses, not a growing region). Resolved directly, no dispatch needed -- same pattern verified at all 4 sample points before writing up. @@ -160,7 +160,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `c` function existence: tree-sitter, ctags agree, GitGalaxy differ -*2-vs-1 -- 3 occurrences as of 2026-08-21T11:59:44Z* +*2-vs-1 -- 3 occurrences as of 2026-08-21T13:27:24Z* **Verdict** (by Claude Sonnet 5 (resolved directly, no dispatch needed), 2026-08-19T00:00:00Z): > Not a new finding -- both sampled names are ALREADY in tree_sitter_accuracy_audit.py's _C_KNOWN_MACRO_HALLUCINATIONS exclusion set (confirmed by grep: 'EXPORT_FUN' and 'MICROPY_WRAP_MP_EXECUTE_BYTECODE' both present). This shape is the same already-documented macro-hallucination mechanism (Claim 8) as the earlier tree-sitter-alone shape, just with ctags ALSO independently hallucinating the same 2 names the same way (both tools' regex/grammar parsers get fooled by the same macro-definition text). GitGalaxy correctly excludes both. Resolved directly, no dispatch needed. @@ -173,7 +173,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `c` function existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 3 occurrences as of 2026-08-21T11:59:44Z* +*2-vs-1 -- 3 occurrences as of 2026-08-21T13:27:24Z* **Verdict** (by Gemini (dispatched via tri-comparison-ledger-sweep), confirmed by Claude Sonnet 5, 2026-08-19T00:00:00Z): > Two distinct causes, both confirmed by independent verification, not one -- resolved via dispatched investigation plus direct fixes. (1) 5 of 8 (I_AllocLow, I_ZoneBase, I_BaseTiccmd, R_CheckBBox, R_AddLine, all doom): a real bug in THIS tool's OWN ctags_reader.py, not a ctags limitation. Old Doom source uses literal TAB characters for column alignment (e.g. `byte*\tI_AllocLow(int length)`); ctags faithfully echoes that tab into its tag-file's address/pattern field, and read_ctags_symbols' naive line.split('\t') then misreads a fragment of the SOURCE LINE as the kind field, fails the kind-membership check, and silently drops the symbol. Confirmed by running ctags with the exact flags this code uses and inspecting the raw tab-delimited output directly -- reproduced the exact column-shift byte for byte. Fixed: parse now finds the tag-file format's guaranteed `;"` address-terminator marker instead of blind-splitting the whole line, only tab-splitting the safe trailer after it. Verified: all 5 names now correctly found. (2) 3 of 8 (slot_nb_power, slot_nb_bool, wrap_next, all cpython typeobject.c): extension of the already-documented SLOT-macro ctags limitation -- each follows a SLOT1BINFULL/SLOT0/RICHCMP_WRAPPER macro invocation ctags misreads as a function (confirmed at typeobject.c:10574/10577/10630), which also swallows the real function immediately after it. Not code-fixed (same ground-truth-judgment reasoning as the sibling 7-occurrence shape) -- already covered by ctags_reader.py's existing note on this mechanism. @@ -186,7 +186,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `c` function args: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T11:59:44Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:27:24Z* **Verdict** (by Claude Sonnet 5 (resolved + fixed directly, no dispatch needed), 2026-08-19T00:00:00Z): > Not a GitGalaxy or ctags defect -- a bug in this tool's OWN _count_ctags_signature_params (tri_comparison_gatherer.py), now fixed. Confirmed directly: ran ctags against cpython/ceval.c, PyEval_GetLocals(void)'s raw signature field is literally the text '(void)'. GitGalaxy and tree-sitter both already special-case C's explicit empty-parameter-list idiom (0 real args, matching detector.py's own _count_top_level_args docstring) -- _count_ctags_signature_params did not, splitting '(void)' into one non-empty segment and counting it as 1 real parameter (the same class of bug its own docstring already describes fixing twice for Python's trailing-comma and bare * / marker cases). Added 'void' to the segment-exclusion set alongside the existing '*'/'/'/'**' -- verified fix: _count_ctags_signature_params('(void)') now returns 0. This corpus (cpython) uses the (void) idiom extremely heavily, plausibly explaining most/all of the 104 occurrences; not independently re-verified beyond the sample, but the mechanism is unconditional (any '(void)' signature was miscounted the same way, corpus-wide) so high confidence it generalizes. No GitHub issue needed -- fixed directly in this same commit, not a repo-code defect. @@ -199,7 +199,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `cobol` function existence: ctags agree, GitGalaxy differ -*2-vs-1 -- 136 occurrences as of 2026-08-21T11:59:49Z* +*2-vs-1 -- 136 occurrences as of 2026-08-21T13:27:29Z* **Verdict** (by gemini-3.1-pro-high (agy), dispatched via tri-comparison-ledger-sweep, reviewed by claude-sonnet-5, 2026-08-19): > Mixed-cause shape, majority ctags-side false positives plus a smaller hidden GitGalaxy defect. (1) Majority (all 10 capped examples, all named END-IF): Universal Ctags' COBOL parser tags ANY period-terminated word as a 'paragraph' (kind p), including scope terminators like END-IF./END-PERFORM. that are not paragraph definitions -- confirmed by a live ctags run on cics-banking-sample-application-cbsa/BANKDATA.cbl showing dozens of plain 'END-IF.' lines (e.g. lines 455, 600) tagged as paragraphs. GitGalaxy correctly excludes these via its END-[A-Za-z0-9_-]+ reserved-word shield. This is a permanent, structural ctags limitation (documented in tests/tools/ctags_reader.py), not a GitGalaxy defect. (2) A smaller (~20 of 133), genuine GitGalaxy false-negative hiding underneath: cics-genapp/lgdpol01.cbl:139 'DELETE-POLICY-DB2-INFO.' and lgapol01.cbl:137 'WRITE-ERROR-MESSAGE.' are real, called (PERFORM'd) paragraph definitions that GitGalaxy's own func_start regex wrongly excludes -- its reserved-word negative lookahead ends in a bare \b, and since '-' is a non-word character in Python re, any real paragraph name that happens to start with a banned keyword followed by a hyphen (a common COBOL verb-prefixed naming convention: WRITE-*, READ-*, SET-*, DELETE-*, ...) is wrongly rejected. Verified directly against the compiled regex (both return no match) and confirmed ~20 such real paragraphs exist corpus-wide via grep. Filed as GitHub issue #1892. Investigated via gemini-3.1-pro-high (agy), file:line citations and regex behavior independently re-verified by Claude before applying. @@ -219,7 +219,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `cobol` function existence: GitGalaxy agree, ctags differ -*2-vs-1 -- 43 occurrences as of 2026-08-21T11:59:49Z* +*2-vs-1 -- 43 occurrences as of 2026-08-21T13:27:29Z* **Verdict** (by gemini-3.1-pro-high (agy), dispatched via tri-comparison-ledger-sweep, reviewed by claude-sonnet-5, 2026-08-19): > Mixed-cause shape, two independent confirmed defects, neither in GitGalaxy's core function detection being right or wrong as a whole. (1) MAINLINE/TIMESTAMP and most of the 18 cases: these are real COBOL SECTION headers in the PROCEDURE DIVISION (e.g. cics-genapp/lgacdb01.cbl:128 "MAINLINE SECTION.", cics-banking-sample-application-cbsa/BANKDATA.cbl:1441 "TIMESTAMP SECTION." followed by executable CALL statements) that GitGalaxy correctly captures per its own documented func_start scope ("Paragraphs and Sections") -- and ctags ALSO correctly tags them, as kind 'section' (verified via live ), not as the 'paragraph' kind. The disagreement is manufactured by tests/tools/ctags_reader.py's CTAGS_FUNC_KINDS["cobol"] = {"p"}, which drops section-kind tags before comparison -- a test-harness bug, not a real ctags-vs-GitGalaxy disagreement. Filed as GitHub issue #1891. (2) LOCAL-STORAGE (cics-banking-sample-application-cbsa/XFRFUN.cbl:107 "LOCAL-STORAGE SECTION." immediately followed by 01-level data item declarations, no executable logic): this is a genuine GitGalaxy false positive -- the func_start regex's reserved-word negative lookahead bans WORKING-STORAGE and LINKAGE as Data Division section names but omits LOCAL-STORAGE, so it slips through and gets miscounted as a paragraph. ctags correctly reports nothing here. Filed as GitHub issue #1890. Investigated via gemini-3.1-pro-high (agy), file:line citations independently re-verified by Claude against language_standards.py and a live ctags run before applying. @@ -239,49 +239,32 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ## cpp -### ❓ `cpp` function existence: GitGalaxy, tree-sitter agree, ctags differ +### ✅ `cpp` function existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 1097 occurrences as of 2026-08-21T11:59:54Z* +*2-vs-1 -- 105 occurrences as of 2026-08-21T13:27:34Z* -**Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`cpp/function/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. +**Verdict** (by Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep, 2026-08-21T00:00:00Z): +> Two distinct causes, both confirmed via direct source reading. (1) The overwhelming majority of this shape (confirmed on samples spanning NVDA/storage.cpp, godot/*, mlir/flatbuffer_export.cc) was a bug in THIS repo's own ctags_reader.py: ctags reports an out-of-class method's bare, unqualified name (`getLineOffsets`) plus a separate scope field, while GitGalaxy/tree-sitter both read the fully-qualified identifier straight from source text (`VBufStorage_buffer_t::getLineOffsets`) -- the two never matched by name. Fixed in this session (`_QUALIFY_NAME_WITH_SCOPE`, `_cpp_qualified_name_candidates`, `--pattern-length-limit=0`, all in ctags_reader.py) by re-joining name+scope from ctags' own tag data, gated on the literal qualified text actually appearing in the tag's verbatim source line so an ordinary in-class-body method (never qualified in source) isn't wrongly qualified too. This alone resolved ~1000 of the original 1097 occurrences. (2) The remainder (105 after the fix, dominated 10/10 sampled by the literal name `OPCODE`) is a genuine, different cause: godot/gdscript_vm.cpp's bytecode interpreter uses `#define OPCODE(m_op) case m_op:` -- a macro invocation used as a switch-case label, not a function call. Both GitGalaxy's func_start regex AND tree-sitter's cpp grammar independently misparse the repeated `OPCODE(OP_X) { ... }` shape as if it were a function definition named `OPCODE`; ctags correctly does not. This is a genuine shared mistake, not real corroboration. | file | name | GitGalaxy | tree-sitter | ctags | |---|---|---|---|---| -| NVDA/storage.cpp | `VBufStorage_buffer_t::getLineOffsets` | 1066 | 1066 | *(n/a)* | -| NVDA/storage.cpp | `VBufStorage_buffer_t::findNodeByAttributes` | 973 | 973 | *(n/a)* | -| NVDA/storage.cpp | `VBufStorage_fieldNode_t::nextNodeInTree` | 57 | 57 | *(n/a)* | -| NVDA/storage.cpp | `VBufStorage_buffer_t::insertNode` | 445 | 445 | *(n/a)* | -| NVDA/storage.cpp | `VBufStorage_buffer_t::unlinkFieldNode` | 766 | 766 | *(n/a)* | -| NVDA/storage.cpp | `VBufStorage_buffer_t::replaceSubtrees` | 642 | 642 | *(n/a)* | -| NVDA/storage.cpp | `VBufStorage_fieldNode_t::getTextInRange` | 274 | 274 | *(n/a)* | -| NVDA/storage.cpp | `VBufStorage_buffer_t::addTextFieldNode` | 585 | 585 | *(n/a)* | -| NVDA/storage.cpp | `VBufStorage_buffer_t::addTextFieldNode` | 623 | 623 | *(n/a)* | -| NVDA/storage.cpp | `VBufStorage_fieldNode_t::generateAttributesForMarkupOpeningTag` | 225 | 225 | *(n/a)* | +| godot/gdscript_vm.cpp | `OPCODE` | 761 | 761 | *(n/a)* | +| godot/gdscript_vm.cpp | `OPCODE` | 848 | 848 | *(n/a)* | +| godot/gdscript_vm.cpp | `OPCODE` | 865 | 865 | *(n/a)* | +| godot/gdscript_vm.cpp | `OPCODE` | 879 | 879 | *(n/a)* | +| godot/gdscript_vm.cpp | `OPCODE` | 902 | 902 | *(n/a)* | +| godot/gdscript_vm.cpp | `OPCODE` | 932 | 932 | *(n/a)* | +| godot/gdscript_vm.cpp | `OPCODE` | 954 | 954 | *(n/a)* | +| godot/gdscript_vm.cpp | `OPCODE` | 988 | 988 | *(n/a)* | +| godot/gdscript_vm.cpp | `OPCODE` | 1034 | 1034 | *(n/a)* | +| godot/gdscript_vm.cpp | `OPCODE` | 1068 | 1068 | *(n/a)* | -### ❓ `cpp` function existence: ctags agree, GitGalaxy, tree-sitter differ +### ✅ `cpp` function existence: tree-sitter agree, GitGalaxy, ctags differ -*2-vs-1 -- 1074 occurrences as of 2026-08-21T11:59:54Z* +*2-vs-1 -- 98 occurrences as of 2026-08-21T13:27:34Z* -**Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`cpp/function/existence/agree[ctags]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. - -| file | name | GitGalaxy | tree-sitter | ctags | -|---|---|---|---|---| -| NVDA/storage.cpp | `VBufStorage_buffer_t` | *(n/a)* | *(n/a)* | 539 | -| NVDA/storage.cpp | `VBufStorage_controlFieldNodeIdentifier_t` | *(n/a)* | *(n/a)* | 36 | -| NVDA/storage.cpp | `VBufStorage_controlFieldNode_t` | *(n/a)* | *(n/a)* | 373 | -| NVDA/storage.cpp | `VBufStorage_fieldNode_t` | *(n/a)* | *(n/a)* | 313 | -| NVDA/storage.cpp | `VBufStorage_textFieldNode_t` | *(n/a)* | *(n/a)* | 425 | -| NVDA/storage.cpp | `addAttribute` | *(n/a)* | *(n/a)* | 321 | -| NVDA/storage.cpp | `addControlFieldNode` | *(n/a)* | *(n/a)* | 548 | -| NVDA/storage.cpp | `addControlFieldNode` | *(n/a)* | *(n/a)* | 561 | -| NVDA/storage.cpp | `addReferenceNodeToBuffer` | *(n/a)* | *(n/a)* | 1231 | -| NVDA/storage.cpp | `addTextFieldNode` | *(n/a)* | *(n/a)* | 585 | - -### ❓ `cpp` function existence: tree-sitter agree, GitGalaxy, ctags differ - -*2-vs-1 -- 98 occurrences as of 2026-08-21T11:59:54Z* - -**Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`cpp/function/existence/agree[tree_sitter]_vs[ctags,gitgalaxy]`) in `tri_comparison_ledger.json`. +**Verdict** (by Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep, 2026-08-21T00:00:00Z): +> Confirmed real tree-sitter-side artifacts, mixed causes, not chased to a code fix in this pass (would need deeper grammar-level investigation than this sweep's budget). Sample breaks into: (1) bare control-flow keywords ('for' at godot/node.cpp:2518, 'if' at godot/object.cpp:784/827) reported as if they were function NAMES -- tree-sitter's own error-recovery misparsing a control-flow statement as a function_definition-shaped node somewhere nearby, the same general failure class already documented elsewhere in this codebase for other languages (e.g. javascript's #1633 Flow-typed misparse), just not previously confirmed for cpp; (2) 'void' as a function name (3 samples) -- likely the same error-recovery mechanism producing a different malformed node shape; (3) conversion-operator names carrying tree-sitter's own trailing return-type/const-suffix convention (`Object::Connection::operator Variant() const`, `operator=` samples) where GitGalaxy and ctags both agree on the bare form (`operator Variant`) without the suffix -- a tree-sitter-side node-name-construction convention difference (in `tsaa._get_node_name`), confirmed to affect ~56 occurrences corpus-wide during this sweep but not isolated to a specific code change given how heavily special-cased and widely shared that helper already is across many languages. No credit/debit applied -- tree-sitter is the one that's wrong here, alone, so there's no consensus for ctags/GitGalaxy to be credited toward (they already agree with each other and are excluded from this shape entirely). | file | name | GitGalaxy | tree-sitter | ctags | |---|---|---|---|---| @@ -296,87 +279,92 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest | godot/object.h | `void` | *(n/a)* | 552 | *(n/a)* | | godot/object.h | `void` | *(n/a)* | 561 | *(n/a)* | -### ❓ `cpp` class existence: GitGalaxy, tree-sitter agree, ctags differ +### ✅ `cpp` class existence: GitGalaxy agree, tree-sitter, ctags differ -*2-vs-1 -- 95 occurrences as of 2026-08-21T11:59:54Z* +*2-vs-1 -- 84 occurrences as of 2026-08-21T13:27:34Z* -**Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`cpp/class/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. +**Verdict** (by Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep, 2026-08-21T00:00:00Z): +> Confirmed real GitGalaxy defect, filed as https://github.com/squid-protocol/gitgalaxy/issues/2011 . GitGalaxy's own class_start regex counts a bare forward declaration (`class AudioStreamPreviewGenerator;`, godot/editor_node.h:68 and 83 more of the same shape in the same file) as if it were a real class definition -- `_CLASS_START_REQUIRES_BODY_ANCHOR` in detector.py, the exact mechanism that already guards against this for C, was never extended to cpp. This session's own tree-sitter walker (tri_comparison_gatherer.py / tree_sitter_accuracy_audit.py) had the identical `lang == "c"`-only gap and has been fixed here (both now check `node.child_by_field_name("body") is None`); the production engine fix is deliberately NOT attempted in the same pass because C++ multiple inheritance (`class Foo : public A, public B {`) makes the existing C-only lookahead regex (which stops at the first `{`/`;`/`,`/`)`/`=`) unsafe to reuse as-is for cpp -- confirmed via direct regex testing that a real multi-inheritance class would be falsely excluded. See issue #2011 for the full design note. | file | name | GitGalaxy | tree-sitter | ctags | |---|---|---|---|---| -| godot/editor_node.h | `AcceptDialog` | *(n/a)* | 45 | *(n/a)* | -| godot/editor_node.h | `ColorPicker` | *(n/a)* | 46 | *(n/a)* | -| godot/editor_node.h | `ConfirmationDialog` | *(n/a)* | 47 | *(n/a)* | -| godot/editor_node.h | `Control` | *(n/a)* | 48 | *(n/a)* | -| godot/editor_node.h | `FileDialog` | *(n/a)* | 49 | *(n/a)* | -| godot/editor_node.h | `HBoxContainer` | *(n/a)* | 50 | *(n/a)* | -| godot/editor_node.h | `ImageTexture` | *(n/a)* | 51 | *(n/a)* | -| godot/editor_node.h | `MenuBar` | *(n/a)* | 52 | *(n/a)* | -| godot/editor_node.h | `MenuButton` | *(n/a)* | 53 | *(n/a)* | -| godot/editor_node.h | `OptionButton` | *(n/a)* | 54 | *(n/a)* | +| godot/editor_node.h | `AcceptDialog` | *(n/a)* | *(n/a)* | *(n/a)* | +| godot/editor_node.h | `ColorPicker` | *(n/a)* | *(n/a)* | *(n/a)* | +| godot/editor_node.h | `ConfirmationDialog` | *(n/a)* | *(n/a)* | *(n/a)* | +| godot/editor_node.h | `Control` | *(n/a)* | *(n/a)* | *(n/a)* | +| godot/editor_node.h | `FileDialog` | *(n/a)* | *(n/a)* | *(n/a)* | +| godot/editor_node.h | `HBoxContainer` | *(n/a)* | *(n/a)* | *(n/a)* | +| godot/editor_node.h | `ImageTexture` | *(n/a)* | *(n/a)* | *(n/a)* | +| godot/editor_node.h | `MenuBar` | *(n/a)* | *(n/a)* | *(n/a)* | +| godot/editor_node.h | `MenuButton` | *(n/a)* | *(n/a)* | *(n/a)* | +| godot/editor_node.h | `OptionButton` | *(n/a)* | *(n/a)* | *(n/a)* | -### ❓ `cpp` function existence: GitGalaxy agree, tree-sitter, ctags differ +### ✅ `cpp` function args: tree-sitter, ctags agree, GitGalaxy differ -*2-vs-1 -- 62 occurrences as of 2026-08-21T11:59:54Z* +*2-vs-1 -- 60 occurrences as of 2026-08-21T13:27:34Z* -**Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`cpp/function/existence/agree[gitgalaxy]_vs[ctags,tree_sitter]`) in `tri_comparison_ledger.json`. +**Verdict** (by Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep, 2026-08-21T00:00:00Z): +> Confirmed real GitGalaxy args-counting defect, filed as https://github.com/squid-protocol/gitgalaxy/issues/2012 . Two distinct sub-patterns visible in the sample: (1) zero-undercounting for out-of-class method definitions with real parameters (VBufStorage_buffer_t::replaceSubtrees, Translator::BuildBuffer, Translator::BuildVhloCompositeV1Op, and every `operator()` call-operator overload in godot/node.h) where ctags and tree-sitter both correctly count real, non-zero parameter lists and GitGalaxy reads 0; (2) an off-by-one OVERcount for a constructor with a member-initializer-list but zero real parameters (VBufStorage_buffer_t's default constructor -- ctags/tree-sitter correctly read 0 params, GitGalaxy reads 1). Not the same shape as the func_start recall gaps in #2009/#2010 -- these are all functions GitGalaxy already finds, just with the wrong parameter count. Needs its own dedicated investigation per the issue (may be one or two root causes). | file | name | GitGalaxy | tree-sitter | ctags | |---|---|---|---|---| -| godot/gdscript_vm.cpp | `GDScriptFunction::call` | 499 | *(n/a)* | *(n/a)* | -| godot/gdscript_vm.cpp | `OPCODE_WHILE` | 754 | *(n/a)* | *(n/a)* | -| godot/gdscript_vm.cpp | `OPCODE_WHILE` | 757 | *(n/a)* | *(n/a)* | -| godot/gdscript_vm.cpp | `OPCODE_SWITCH` | 760 | *(n/a)* | *(n/a)* | -| godot/gdscript_vm.cpp | `OPCODE` | 3944 | *(n/a)* | *(n/a)* | -| godot/main.cpp | `Main::setup` | 1027 | *(n/a)* | *(n/a)* | -| godot/main.cpp | `Main::setup2` | 3007 | *(n/a)* | *(n/a)* | -| godot/main.cpp | `Main::start` | 3987 | *(n/a)* | *(n/a)* | -| godot/object.cpp | `Object::Connection::operator Variant` | 108 | *(n/a)* | *(n/a)* | -| godot/variant.cpp | `Variant::operator Vector4i` | 1855 | *(n/a)* | *(n/a)* | +| NVDA/storage.cpp | `VBufStorage_buffer_t::replaceSubtrees` | 0 | 1 | 1 | +| NVDA/storage.cpp | `VBufStorage_buffer_t::VBufStorage_buffer_t` | 1 | 0 | 0 | +| godot/node.h | `operator()` | 0 | 2 | 2 | +| godot/node.h | `operator()` | 0 | 2 | 2 | +| godot/node.h | `operator()` | 0 | 2 | 2 | +| godot/node.h | `operator()` | 0 | 2 | 2 | +| godot/variant.cpp | `operator<` | 0 | 1 | 1 | +| godot/variant.h | `operator()` | 0 | 2 | 2 | +| mlir/flatbuffer_export.cc | `Translator::BuildBuffer` | 0 | 3 | 3 | +| mlir/flatbuffer_export.cc | `Translator::BuildVhloCompositeV1Op` | 0 | 4 | 4 | -### ❓ `cpp` class existence: tree-sitter agree, GitGalaxy, ctags differ +### ✅ `cpp` function existence: GitGalaxy, ctags agree, tree-sitter differ -*2-vs-1 -- 22 occurrences as of 2026-08-21T11:59:54Z* +*2-vs-1 -- 60 occurrences as of 2026-08-21T13:27:34Z* -**Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`cpp/class/existence/agree[tree_sitter]_vs[ctags,gitgalaxy]`) in `tri_comparison_ledger.json`. +**Verdict** (by Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep, 2026-08-21T00:00:00Z): +> Confirmed real tree-sitter-cpp grammar limitation, not a GitGalaxy or ctags defect. Every sampled case (GDScriptFunction::call, Main::setup, Main::setup2, Main::start, Object::Connection::operator Variant) is a large, complex function -- GDScriptFunction::call in particular (godot/gdscript_vm.cpp:499) is a bytecode interpreter's main dispatch loop using GNU 'labels as values' computed-goto syntax (`&&OPCODE_LABEL`) via the same OPCODES_TABLE/OPCODE macro family documented in the sibling agree[gitgalaxy,tree_sitter]_vs[ctags] entry -- a non-standard GNU extension tree-sitter-cpp's grammar does not support, which plausibly causes a parse error cascade that loses the enclosing function_definition node entirely rather than just misreading the body. ctags and GitGalaxy both correctly find and name these functions regardless of body content, since neither one needs to fully parse the function body to recognize its signature. tree-sitter's non-detection is a confirmed limitation in tree-sitter itself -- but no credit_tools adjustment applies: ctags and GitGalaxy are already a 2-of-3 AGREEING PAIR on this shape (agreeing_tools has 2 members), which already satisfies reconcile_symbols' own `len(present) >= 2` precision-credit condition naturally with no ledger adjustment needed. credit_tools exists for a LONE, single-tool claim (agreeing_tools with exactly 1 member) the base algorithm can't otherwise corroborate -- applying it to an already-mutually-corroborating pair would double-count (confirmed: this exact mistake briefly pushed ctags' precision past 100% before being caught and reverted in this same session). | file | name | GitGalaxy | tree-sitter | ctags | |---|---|---|---|---| -| godot/editor_node.h | `SceneNameCasing` | *(n/a)* | 124 | *(n/a)* | -| godot/editor_node.h | `ActionOnPlay` | *(n/a)* | 132 | *(n/a)* | -| godot/editor_node.h | `ActionOnStop` | *(n/a)* | 138 | *(n/a)* | -| godot/editor_node.h | `MenuOptions` | *(n/a)* | 143 | *(n/a)* | -| godot/editor_node.h | `MenuType` | *(n/a)* | 711 | *(n/a)* | -| godot/main.h | `CLIOptionAvailability` | *(n/a)* | 40 | *(n/a)* | -| godot/main.h | `CLIScope` | *(n/a)* | 64 | *(n/a)* | -| godot/node.h | `ProcessMode` | *(n/a)* | 79 | *(n/a)* | -| godot/node.h | `ProcessThreadGroup` | *(n/a)* | 87 | *(n/a)* | -| godot/node.h | `ProcessThreadMessages` | *(n/a)* | 93 | *(n/a)* | +| godot/gdscript_vm.cpp | `GDScriptFunction::call` | 499 | *(n/a)* | 499 | +| godot/main.cpp | `Main::setup` | 1027 | *(n/a)* | 1027 | +| godot/main.cpp | `Main::setup2` | 3007 | *(n/a)* | 3007 | +| godot/main.cpp | `Main::start` | 3987 | *(n/a)* | 3987 | +| godot/object.cpp | `Object::Connection::operator Variant` | 108 | *(n/a)* | 108 | +| godot/object.h | `RequiredResult` | 994 | *(n/a)* | 995 | +| godot/object.h | `RequiredResult` | 1003 | *(n/a)* | 1004 | +| godot/object.h | `RequiredResult` | 1012 | *(n/a)* | 1013 | +| godot/object.h | `RequiredParam` | 1130 | *(n/a)* | 1131 | +| godot/object.h | `operator ptr_type` | 1031 | *(n/a)* | 1031 | -### ❓ `cpp` function args: tree-sitter, ctags agree, GitGalaxy differ +### ✅ `cpp` function existence: ctags agree, GitGalaxy, tree-sitter differ -*2-vs-1 -- 15 occurrences as of 2026-08-21T11:59:54Z* +*2-vs-1 -- 30 occurrences as of 2026-08-21T13:27:34Z* -**Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`cpp/function/args/agree[ctags,tree_sitter]_vs[gitgalaxy]`) in `tri_comparison_ledger.json`. +**Verdict** (by Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep, 2026-08-21T00:00:00Z): +> Confirmed ctags-only limitation: ctags parses INSIDE C++ macro DEFINITION bodies as if they were real, already-expanded code. godot/object.h's GDCLASS/_FORCE_INLINE_-based macros (`#define GDCLASS(m_class, m_inherits) ... _FORCE_INLINE_ bool (Object::*_get_get() const)(...) {...} ...`) never run as written -- they only produce real code once expanded at a `GDCLASS(SomeClass, Base)` call site elsewhere -- but ctags tags `_get_get`/`_get_set`/`_get_bind_methods`/`_get_bind_compatibility_methods`/`_get_notification`/`_get_property_can_revert`/`_get_property_get_revert`/`_get_validate_property`/`_get_get_property_list` (all 9 sampled cases, all from this same macro) as if they were ordinary member functions. Neither GitGalaxy nor tree-sitter are fooled by this. Documented in ctags_reader.py's KIND MAPS section (cpp bullet) rather than fixed -- this is ctags' own parser behavior, nothing in this repo's tooling can distinguish a macro-definition body from real code without reimplementing preprocessing. | file | name | GitGalaxy | tree-sitter | ctags | |---|---|---|---|---| -| mlir/flatbuffer_export.cc | `CreateLocation` | 0 | 5 | 5 | -| mlir/flatbuffer_export.cc | `GetStringsFromDictionaryAttr` | 0 | 2 | 2 | -| mlir/flatbuffer_export.cc | `CreateOpLocation` | 0 | 5 | 5 | -| mlir/flatbuffer_export.cc | `MlirToFlatBufferTranslateFunction` | 0 | 3 | 3 | -| mlir/flatbuffer_export.cc | `MlirToFlatBufferTranslateFunction` | 0 | 4 | 4 | -| mlir/flatbuffer_export.cc | `GetTensorFlowNodeDef` | 0 | 1 | 1 | -| mlir/flatbuffer_export.cc | `GetStringsFromAttrWithSeparator` | 0 | 2 | 2 | -| mlir/flatbuffer_export.cc | `IsUnsupportedLocation` | 0 | 1 | 1 | -| mlir/mlir_bridge_rollout_policy.cc | `GetMlirBridgeRolloutPolicy` | 0 | 6 | 6 | -| mlir/mlir_graph_optimization_pass.cc | `DumpModule` | 0 | 2 | 2 | +| godot/object.h | `_get_bind_compatibility_methods` | *(n/a)* | *(n/a)* | 552 | +| godot/object.h | `_get_bind_methods` | *(n/a)* | *(n/a)* | 549 | +| godot/object.h | `_get_get` | *(n/a)* | *(n/a)* | 555 | +| godot/object.h | `_get_get_property_list` | *(n/a)* | *(n/a)* | 561 | +| godot/object.h | `_get_notification` | *(n/a)* | *(n/a)* | 573 | +| godot/object.h | `_get_property_can_revert` | *(n/a)* | *(n/a)* | 567 | +| godot/object.h | `_get_property_get_revert` | *(n/a)* | *(n/a)* | 570 | +| godot/object.h | `_get_set` | *(n/a)* | *(n/a)* | 558 | +| godot/object.h | `_get_validate_property` | *(n/a)* | *(n/a)* | 564 | +| godot/object.h | `operator Ref` | *(n/a)* | *(n/a)* | 1036 | -### ❓ `cpp` function args: GitGalaxy, ctags agree, tree-sitter differ +### ✅ `cpp` function args: GitGalaxy, ctags agree, tree-sitter differ -*2-vs-1 -- 13 occurrences as of 2026-08-21T11:59:54Z* +*2-vs-1 -- 13 occurrences as of 2026-08-21T13:27:34Z* -**Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`cpp/function/args/agree[ctags,gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. +**Verdict** (by Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep, 2026-08-21T00:00:00Z): +> Confirmed real tree-sitter accuracy-tool limitation, filed separately (see the sibling agree[none]_vs[ctags,gitgalaxy,tree_sitter] args entry and its referenced issue for the full writeup). tree-sitter's own parameter count (via the shared `_get_param_count` helper in tree_sitter_accuracy_audit.py, reused by tri_comparison_gatherer.py) undercounts by exactly 1 whenever a function has a parameter with a default value -- confirmed 6/6 sampled cases (save_scene_to_path, step, get_index, atr_n, atr, ObjectSignalLock), all off by exactly 1, all involving a `= default_value` parameter, ctags and GitGalaxy both correctly counting the real total. No credit_tools/debit_tools adjustment applies -- this is an args-metric shape, and apply_verified_adjustments only ever touches existence-metric precision (args scores have no equivalent verified-adjustment mechanism in this ledger's own code, see tri_comparison_ledger.py's apply_verified_adjustments docstring), so these fields would be a pure no-op here regardless of value -- left empty rather than set-but-inert, for an accurate record. | file | name | GitGalaxy | tree-sitter | ctags | |---|---|---|---|---| @@ -391,49 +379,67 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest | godot/object.h | `RequiredParam` | 1 | 0 | 1 | | godot/rendering_server_default.h | `shader_create_from_code` | 2 | 1 | 2 | -### ❓ `cpp` function existence: GitGalaxy, ctags agree, tree-sitter differ +### ✅ `cpp` function existence: GitGalaxy agree, tree-sitter, ctags differ -*2-vs-1 -- 8 occurrences as of 2026-08-21T11:59:54Z* +*2-vs-1 -- 10 occurrences as of 2026-08-21T13:27:34Z* -**Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`cpp/function/existence/agree[ctags,gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. +**Verdict** (by Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep, 2026-08-21T00:00:00Z): +> Compound shape, three distinct causes confirmed via source, not one. (1) Most of the sample (OPCODE_WHILE x2, OPCODE_SWITCH, OPCODE) is the same GG+tree-sitter shared macro-misparse family documented in the sibling agree[gitgalaxy,tree_sitter]_vs[ctags] entry (godot/gdscript_vm.cpp's OPCODE/OPCODE_WHILE/OPCODE_SWITCH dispatch macros) -- here landing as 'GitGalaxy alone' because tree-sitter's own error recovery on this repeated macro pattern isn't fully deterministic across every occurrence, not because the underlying cause differs. GitGalaxy is WRONG for this portion (same debit as the sibling entry, not double-counted here since debit_tools is per-shape). (2) `attribute_buffer_applier_factories_`/`m_draggingState`/`std::thread` are a separate, real GitGalaxy FALSE POSITIVE: a lambda passed as a constructor argument or member-initializer-list entry (`m_draggingState([this]() {...}),`, `std::thread([...]() {...}).detach();`) is misread as a function definition. Filed as https://github.com/squid-protocol/gitgalaxy/issues/2013 . (3) `Variant::operator ::RID`/`Variant::operator ::AABB`/`Variant::operator Object *` are real functions GitGalaxy correctly finds (confirmed via godot/variant.cpp source) that didn't rank-match ctags/tree-sitter's own readings of the same functions by exact name string -- a residual, low-priority naming-comparison edge case (global-scope `::`-prefixed conversion-operator return types) not chased further in this pass. No credit/debit applied given the mixed, three-cause nature of this shape. | file | name | GitGalaxy | tree-sitter | ctags | |---|---|---|---|---| -| godot/object.h | `RequiredResult` | 994 | *(n/a)* | 995 | -| godot/object.h | `RequiredResult` | 1003 | *(n/a)* | 1004 | -| godot/object.h | `RequiredResult` | 1012 | *(n/a)* | 1013 | -| godot/object.h | `RequiredParam` | 1130 | *(n/a)* | 1131 | -| godot/object.h | `operator ptr_type` | 1031 | *(n/a)* | 1031 | -| godot/variant.h | `~Variant` | 873 | *(n/a)* | 873 | -| godot/variant.h | `~PackedArrayRefBase` | 217 | *(n/a)* | 217 | -| godot/variant.h | `operator T` | 476 | *(n/a)* | 477 | +| godot/gdscript_vm.cpp | `OPCODE_WHILE` | 754 | *(n/a)* | *(n/a)* | +| godot/gdscript_vm.cpp | `OPCODE_WHILE` | 757 | *(n/a)* | *(n/a)* | +| godot/gdscript_vm.cpp | `OPCODE_SWITCH` | 760 | *(n/a)* | *(n/a)* | +| godot/gdscript_vm.cpp | `OPCODE` | 3944 | *(n/a)* | *(n/a)* | +| godot/variant.cpp | `Variant::operator ::RID` | 2002 | *(n/a)* | *(n/a)* | +| godot/variant.cpp | `Variant::operator ::AABB` | 1882 | *(n/a)* | *(n/a)* | +| godot/variant.cpp | `Variant::operator Object *` | 2024 | *(n/a)* | *(n/a)* | +| mlir/flatbuffer_export.cc | `attribute_buffer_applier_factories_` | 679 | *(n/a)* | *(n/a)* | +| powertoys/FancyZones.cpp | `m_draggingState` | 75 | *(n/a)* | *(n/a)* | +| powertoys/main.cpp | `std::thread` | 88 | *(n/a)* | *(n/a)* | -### ❓ `cpp` class existence: ctags agree, GitGalaxy, tree-sitter differ +### ✅ `cpp` class existence: ctags agree, GitGalaxy, tree-sitter differ -*2-vs-1 -- 2 occurrences as of 2026-08-21T11:59:54Z* +*2-vs-1 -- 2 occurrences as of 2026-08-21T13:27:34Z* -**Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`cpp/class/existence/agree[ctags]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. +**Verdict** (by Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep, 2026-08-21T00:00:00Z): +> Not a real existence disagreement -- a template-argument name-formatting difference in the comparison tooling. `godot/variant.h`'s `HashMapComparatorDefault` and `is_zero_constructible` are template CLASS specializations; GitGalaxy and tree-sitter both read the name WITH its template argument baked in (matching the instantiation as written in source), while ctags strips the `<...>` template-argument suffix from its own class tag name. All three tools found the exact same class definition at the exact same line -- confirmed via the sibling agree[gitgalaxy,tree_sitter]_vs[ctags] entry, which is the same pair of classes from the opposite direction. Low magnitude (2 occurrences) -- not chased to a code fix in this pass, but a plausible future micro-fix would strip a trailing `<...>` from gg/tree-sitter's class name before matching, mirroring how ctags_reader.py's operator-name normalization already handles a similar formatting mismatch. | file | name | GitGalaxy | tree-sitter | ctags | |---|---|---|---|---| | godot/variant.h | `HashMapComparatorDefault` | *(n/a)* | *(n/a)* | 886 | | godot/variant.h | `is_zero_constructible` | *(n/a)* | *(n/a)* | 984 | -### ❓ `cpp` function existence: tree-sitter, ctags agree, GitGalaxy differ +### ✅ `cpp` class existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T11:59:54Z* +*2-vs-1 -- 2 occurrences as of 2026-08-21T13:27:34Z* -**Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`cpp/function/existence/agree[ctags,tree_sitter]_vs[gitgalaxy]`) in `tri_comparison_ledger.json`. +**Verdict** (by Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep, 2026-08-21T00:00:00Z): +> Same template-argument name-formatting difference as the sibling agree[ctags]_vs[gitgalaxy,tree_sitter] class entry, viewed from the opposite direction -- `HashMapComparatorDefault`/`is_zero_constructible` (ctags' bare names) vs. `HashMapComparatorDefault`/`is_zero_constructible` (GitGalaxy/tree-sitter's names, template argument included). Not a real disagreement about whether these classes exist -- see the sibling entry for the full explanation. + +| file | name | GitGalaxy | tree-sitter | ctags | +|---|---|---|---|---| +| godot/variant.h | `HashMapComparatorDefault` | *(n/a)* | 886 | *(n/a)* | +| godot/variant.h | `is_zero_constructible` | *(n/a)* | 984 | *(n/a)* | + +### ✅ `cpp` function existence: tree-sitter, ctags agree, GitGalaxy differ + +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:27:34Z* + +**Verdict** (by Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep, 2026-08-21T00:00:00Z): +> The single sampled occurrence (mlir/flatbuffer_export.cc:654, the `Translator` class's constructor) is exactly the bug filed as https://github.com/squid-protocol/gitgalaxy/issues/2009 -- a member-initializer-list spanning 906 characters exceeds GitGalaxy's func_start regex's 500-character cap for that clause, so the whole constructor is invisible to GitGalaxy despite ctags and tree-sitter both finding it correctly. GitGalaxy's non-detection is a confirmed, filed limitation -- but no credit_tools adjustment applies: ctags and tree-sitter are already a 2-of-3 AGREEING PAIR on this shape, which already satisfies reconcile_symbols' own `len(present) >= 2` precision-credit condition naturally. See the sibling agree[ctags,gitgalaxy]_vs[tree_sitter] entry for the full explanation of why credit_tools only applies to a LONE, single-tool claim, never an already-agreeing pair. | file | name | GitGalaxy | tree-sitter | ctags | |---|---|---|---|---| | mlir/flatbuffer_export.cc | `Translator` | *(n/a)* | 654 | 654 | -### ❓ `cpp` function args: none agree, GitGalaxy, tree-sitter, ctags differ +### ✅ `cpp` function args: none agree, GitGalaxy, tree-sitter, ctags differ -*3-way split -- 1 occurrence as of 2026-08-21T11:59:54Z* +*3-way split -- 1 occurrence as of 2026-08-21T13:27:34Z* -**Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`cpp/function/args/agree[none]_vs[ctags,gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. +**Verdict** (by Claude Sonnet 5, dispatched via tri-comparison-ledger-sweep, 2026-08-21T00:00:00Z): +> A single function (NVDA/storage.cpp's `outputEscapedAttribute`, `size_t outputEscapedAttribute(wostringstream& out, const wstring& text, size_t maxLength=0)`, 3 real parameters) where all three tools disagree for two already-independently-confirmed reasons, not a new one: ctags reads the correct count (3); GitGalaxy reads 0, matching the args-undercounting defect filed as https://github.com/squid-protocol/gitgalaxy/issues/2012 ; tree-sitter reads 2, matching the default-value-parameter undercount filed as https://github.com/squid-protocol/gitgalaxy/issues/2014 (this function's third parameter, `maxLength`, has a default value -- exactly the trigger condition for that bug). Both referenced issues cover the general pattern; no new finding here beyond confirming they can compound on the same function. | file | name | GitGalaxy | tree-sitter | ctags | |---|---|---|---|---| @@ -443,7 +449,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `csharp` function existence: GitGalaxy, ctags agree, tree-sitter differ -*2-vs-1 -- 271 occurrences as of 2026-08-21T12:00:00Z* +*2-vs-1 -- 271 occurrences as of 2026-08-21T13:27:40Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`csharp/function/existence/agree[ctags,gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. @@ -462,7 +468,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `csharp` function existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 107 occurrences as of 2026-08-21T12:00:00Z* +*2-vs-1 -- 107 occurrences as of 2026-08-21T13:27:40Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`csharp/function/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. @@ -481,7 +487,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `csharp` function existence: GitGalaxy agree, tree-sitter, ctags differ -*2-vs-1 -- 48 occurrences as of 2026-08-21T12:00:00Z* +*2-vs-1 -- 48 occurrences as of 2026-08-21T13:27:40Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`csharp/function/existence/agree[gitgalaxy]_vs[ctags,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -498,9 +504,27 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest | roslyn/LanguageParser.cs | `parseCallingConvention` | 8100 | *(n/a)* | *(n/a)* | | roslyn/LanguageParser.cs | `parseSwitchHeader` | 10175 | *(n/a)* | *(n/a)* | +### ❓ `csharp` class existence: GitGalaxy, ctags agree, tree-sitter differ + +*2-vs-1 -- 9 occurrences as of 2026-08-21T13:27:40Z* + +**Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`csharp/class/existence/agree[ctags,gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. + +| file | name | GitGalaxy | tree-sitter | ctags | +|---|---|---|---|---| +| roslyn/LanguageParser.cs | `LanguageParser` | *(n/a)* | *(n/a)* | 20 | +| roslyn/LanguageParser.cs | `VariableFlags` | *(n/a)* | *(n/a)* | 5379 | +| roslyn/LanguageParser.cs | `NameOptions` | *(n/a)* | *(n/a)* | 5997 | +| roslyn/LanguageParser.cs | `ScanTypeArgumentListKind` | *(n/a)* | *(n/a)* | 6228 | +| roslyn/LanguageParser.cs | `ScanTypeFlags` | *(n/a)* | *(n/a)* | 7115 | +| roslyn/LanguageParser.cs | `ParseTypeMode` | *(n/a)* | *(n/a)* | 7565 | +| roslyn/LanguageParser.cs | `Precedence` | *(n/a)* | *(n/a)* | 11187 | +| roslyn/LanguageParser.cs | `DisposableResetPoint` | *(n/a)* | *(n/a)* | 14575 | +| roslyn/LanguageParser.cs | `ResetPoint` | *(n/a)* | *(n/a)* | 14600 | + ### ❓ `csharp` function args: tree-sitter, ctags agree, GitGalaxy differ -*2-vs-1 -- 7 occurrences as of 2026-08-21T12:00:00Z* +*2-vs-1 -- 7 occurrences as of 2026-08-21T13:27:40Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`csharp/function/args/agree[ctags,tree_sitter]_vs[gitgalaxy]`) in `tri_comparison_ledger.json`. @@ -514,38 +538,9 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest | roslyn/Workspace.cs | `SetCurrentSolutionEx` | 2 | 1 | 1 | | roslyn/Workspace.cs | `ProcessEventHandlerWorkQueueAsync` | 1 | 2 | 2 | -### ❓ `csharp` class existence: GitGalaxy agree, tree-sitter, ctags differ - -*2-vs-1 -- 6 occurrences as of 2026-08-21T12:00:00Z* - -**Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`csharp/class/existence/agree[gitgalaxy]_vs[ctags,tree_sitter]`) in `tri_comparison_ledger.json`. - -| file | name | GitGalaxy | tree-sitter | ctags | -|---|---|---|---|---| -| roslyn/LanguageParser.cs | `VariableFlags` | *(n/a)* | *(n/a)* | *(n/a)* | -| roslyn/LanguageParser.cs | `NameOptions` | *(n/a)* | *(n/a)* | *(n/a)* | -| roslyn/LanguageParser.cs | `ScanTypeArgumentListKind` | *(n/a)* | *(n/a)* | *(n/a)* | -| roslyn/LanguageParser.cs | `ScanTypeFlags` | *(n/a)* | *(n/a)* | *(n/a)* | -| roslyn/LanguageParser.cs | `ParseTypeMode` | *(n/a)* | *(n/a)* | *(n/a)* | -| roslyn/LanguageParser.cs | `Precedence` | *(n/a)* | *(n/a)* | *(n/a)* | - -### ❓ `csharp` class existence: GitGalaxy, tree-sitter agree, ctags differ - -*2-vs-1 -- 5 occurrences as of 2026-08-21T12:00:00Z* - -**Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`csharp/class/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. - -| file | name | GitGalaxy | tree-sitter | ctags | -|---|---|---|---|---| -| roslyn/LanguageParser.cs | `TerminatorState` | *(n/a)* | 57 | *(n/a)* | -| roslyn/LanguageParser.cs | `NamespaceParts` | *(n/a)* | 399 | *(n/a)* | -| roslyn/LanguageParser.cs | `LanguageParserState` | *(n/a)* | 4295 | *(n/a)* | -| roslyn/LanguageParser.cs | `AccessorDeclaringKind` | *(n/a)* | 4342 | *(n/a)* | -| roslyn/LanguageParser.cs | `PostSkipAction` | *(n/a)* | 4472 | *(n/a)* | - ### ❓ `csharp` function args: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 4 occurrences as of 2026-08-21T12:00:00Z* +*2-vs-1 -- 4 occurrences as of 2026-08-21T13:27:40Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`csharp/function/args/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. @@ -558,7 +553,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `csharp` function existence: tree-sitter, ctags agree, GitGalaxy differ -*2-vs-1 -- 4 occurrences as of 2026-08-21T12:00:00Z* +*2-vs-1 -- 4 occurrences as of 2026-08-21T13:27:40Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`csharp/function/existence/agree[ctags,tree_sitter]_vs[gitgalaxy]`) in `tri_comparison_ledger.json`. @@ -569,21 +564,9 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest | roslyn/CSharpSyntaxTree.cs | `GetRoot` | *(n/a)* | 86 | 86 | | roslyn/DiagnosticAnalyzer.cs | `Initialize` | *(n/a)* | 24 | 24 | -### ❓ `csharp` class existence: GitGalaxy, ctags agree, tree-sitter differ - -*2-vs-1 -- 3 occurrences as of 2026-08-21T12:00:00Z* - -**Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`csharp/class/existence/agree[ctags,gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. - -| file | name | GitGalaxy | tree-sitter | ctags | -|---|---|---|---|---| -| roslyn/LanguageParser.cs | `LanguageParser` | *(n/a)* | *(n/a)* | 20 | -| roslyn/LanguageParser.cs | `DisposableResetPoint` | *(n/a)* | *(n/a)* | 14575 | -| roslyn/LanguageParser.cs | `ResetPoint` | *(n/a)* | *(n/a)* | 14600 | - ### ❓ `csharp` function args: GitGalaxy, ctags agree, tree-sitter differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:00:00Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:27:40Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`csharp/function/args/agree[ctags,gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. @@ -593,7 +576,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `csharp` function existence: ctags agree, GitGalaxy, tree-sitter differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:00:00Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:27:40Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`csharp/function/existence/agree[ctags]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -603,7 +586,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `csharp` function existence: tree-sitter agree, GitGalaxy, ctags differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:00:00Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:27:40Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`csharp/function/existence/agree[tree_sitter]_vs[ctags,gitgalaxy]`) in `tri_comparison_ledger.json`. @@ -613,7 +596,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `csharp` function args: none agree, GitGalaxy, tree-sitter, ctags differ -*3-way split -- 1 occurrence as of 2026-08-21T12:00:00Z* +*3-way split -- 1 occurrence as of 2026-08-21T13:27:40Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`csharp/function/args/agree[none]_vs[ctags,gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -625,7 +608,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `css` function existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 3 occurrences as of 2026-08-21T12:00:02Z* +*2-vs-1 -- 3 occurrences as of 2026-08-21T13:27:41Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`css/function/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. @@ -639,7 +622,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `dart` function existence: GitGalaxy agree, tree-sitter differ -*2-vs-1 -- 37 occurrences as of 2026-08-21T12:00:06Z* +*2-vs-1 -- 37 occurrences as of 2026-08-21T13:27:45Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`dart/function/existence/agree[gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. @@ -658,7 +641,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `dart` function existence: tree-sitter agree, GitGalaxy differ -*2-vs-1 -- 18 occurrences as of 2026-08-21T12:00:06Z* +*2-vs-1 -- 18 occurrences as of 2026-08-21T13:27:45Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`dart/function/existence/agree[tree_sitter]_vs[gitgalaxy]`) in `tri_comparison_ledger.json`. @@ -677,7 +660,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `dart` function args: none agree, GitGalaxy, tree-sitter differ -*3-way split -- 216 occurrences as of 2026-08-21T12:00:06Z* +*3-way split -- 216 occurrences as of 2026-08-21T13:27:45Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`dart/function/args/agree[none]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -698,7 +681,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `fortran` function existence: GitGalaxy, ctags agree, tree-sitter differ -*2-vs-1 -- 14 occurrences as of 2026-08-21T12:00:13Z* +*2-vs-1 -- 14 occurrences as of 2026-08-21T13:27:51Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`fortran/function/existence/agree[ctags,gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. @@ -717,7 +700,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `fortran` class existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 8 occurrences as of 2026-08-21T12:00:13Z* +*2-vs-1 -- 8 occurrences as of 2026-08-21T13:27:51Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`fortran/class/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. @@ -734,7 +717,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `fortran` function existence: tree-sitter, ctags agree, GitGalaxy differ -*2-vs-1 -- 2 occurrences as of 2026-08-21T12:00:13Z* +*2-vs-1 -- 2 occurrences as of 2026-08-21T13:27:51Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`fortran/function/existence/agree[ctags,tree_sitter]_vs[gitgalaxy]`) in `tri_comparison_ledger.json`. @@ -745,7 +728,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `fortran` function existence: GitGalaxy agree, tree-sitter, ctags differ -*2-vs-1 -- 2 occurrences as of 2026-08-21T12:00:13Z* +*2-vs-1 -- 2 occurrences as of 2026-08-21T13:27:51Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`fortran/function/existence/agree[gitgalaxy]_vs[ctags,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -756,7 +739,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `fortran` function args: tree-sitter, ctags agree, GitGalaxy differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:00:13Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:27:51Z* **Verdict** (by Claude Sonnet 5, direct investigation (surfaced while re-blessing the tri-comparison chart after #1973/#1985), 2026-08-21T00:00:00Z): > Confirmed GitGalaxy engine defect, ctags and tree-sitter both correct. init_domain (module_initialize_real.F:41, `SUBROUTINE init_domain ( grid )`) genuinely takes 1 parameter. GitGalaxy's own args regex correctly matches '( grid )' when tested in isolation against the real declaration line -- the bug is upstream of the args regex entirely: fortran's func_start regex's optional return-TYPE-prefix group (`(?:INTEGER|REAL|...)[A-Za-z0-9_ \t\n&*,()=:]{0,40}?`) allows up to 40 characters including newlines between the TYPE keyword and the following FUNCTION/SUBROUTINE/etc keyword, with no requirement that they belong to the same statement. In this file, an unrelated, already-terminated `INTEGER :: internal_time_loop` declaration sits ~30 characters (4 blank lines) before `SUBROUTINE init_domain`, so the regex's own match.start() lands on that earlier, unrelated line instead of the real declaration -- corrupting every downstream computation anchored to it (start_line, body span, and -- since #1973's fix correctly bounds the args search to the label's OWN statement span -- the args search window too, which can no longer reach the real '( grid )' text several lines later). Filed as #1982 (not yet fixed). No credit/debit -- ctags and tree-sitter aren't corroborating each other by coincidence here, they're both just correctly parsing real Fortran grammar that GitGalaxy's func_start regex currently mis-anchors. @@ -767,7 +750,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `fortran` function args: none agree, GitGalaxy, tree-sitter, ctags differ -*3-way split -- 1 occurrence as of 2026-08-21T12:00:13Z* +*3-way split -- 1 occurrence as of 2026-08-21T13:27:51Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`fortran/function/args/agree[none]_vs[ctags,gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -779,7 +762,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `go` function args: GitGalaxy, ctags agree, tree-sitter differ -*2-vs-1 -- 75 occurrences as of 2026-08-21T12:00:15Z* +*2-vs-1 -- 75 occurrences as of 2026-08-21T13:27:53Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`go/function/args/agree[ctags,gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. @@ -800,7 +783,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `haskell` function existence: ctags agree, GitGalaxy, tree-sitter differ -*2-vs-1 -- 103 occurrences as of 2026-08-21T12:00:18Z* +*2-vs-1 -- 103 occurrences as of 2026-08-21T13:27:56Z* **Verdict** (by Claude Sonnet 5 (dispatched agent investigation), 2026-08-19T00:00:00Z): > All 10 sampled cases are ctags-side artifacts, not real GitGalaxy/tree-sitter misses -- confirmed via direct `ctags -x` output against the corpus. Three distinct ctags Haskell-parser weaknesses cover the sample: (1) multi-clause double/triple-tagging -- ctags tags every pattern-matched equation line as its own occurrence of the name (writerFn/writeFnBinary/expandFilterPath: confirmed 2-3 raw ctags tags per function, one per clause; a file-wide count found 45 such extra same-name tags across the 7-file corpus, e.g. blockToInlines alone has 14). GitGalaxy/tree-sitter both correctly anchor to the FIRST clause only, leaving ctags' later-clause tags as the ones unpaired. (2) keyword-as-identifier misparsing -- `class`/`where`/`pattern` (from PatternSynonyms) get tagged as function names when ctags fails to parse past the keyword; confirmed at Options.hs:62 (`class HasSyntaxExtensions`), Parsing.hs:184 (module-header `where`), and 3 PatternSynonyms declarations in Options.hs. (3) CAF/value-vs-function kind collapse -- defaultAbbrevs/defaultKaTeXURL/defaultMathJaxURL/defaultWebTeXURL are zero-arg top-level VALUES (non-arrow type signatures), not functions; ctags has no value/variable kind at all (`ctags --list-kinds-full=Haskell` shows only constructor/function/module/type) so it lumps every `name = expr` binding into "function". GitGalaxy (language_standards.py haskell rules, #1312) and tree-sitter's own audit tooling (_find_haskell_signature_for_bind, #1566) both independently make the same value-vs-function distinction correctly -- real cross-tool corroboration, not coincidence. (4) TH-splice call sites misread as definitions -- deriveJSON at Options.hs:454/458 is a Template Haskell splice INVOKING an imported function, not defining one; ctags misparses the call as a definition. No GitGalaxy/tree-sitter defect anywhere in this shape; purely a ctags parser limitation, same category as the already-documented empty CTAGS_CLASS_KINDS['haskell']. @@ -820,7 +803,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `haskell` function existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 69 occurrences as of 2026-08-21T12:00:18Z* +*2-vs-1 -- 69 occurrences as of 2026-08-21T13:27:56Z* **Verdict** (by Claude Sonnet 5 (dispatched agent investigation), 2026-08-19T00:00:00Z): > Confirmed: all 10 sampled misses (and, by cross-check against additional non-sampled instances in Options.hs/Shared.hs, plausibly all 69) are locally-scoped function definitions -- `instance ... where` methods, `where`-clause helpers, or `let`-bound names inside `do` blocks -- never top-level module definitions. ctags' Haskell parser has no layout-rule/scope awareness and only tags equations anchored at column 1; it correctly handles multi-clause TOP-LEVEL definitions (verified via expandFilterPath, writeFnBinary, writerFn -- all tag fine, clauses and all), so this is a pure scope blind spot, not a clause-counting bug (distinct from the tree-sitter clause-splitting bug fixed earlier in this same effort, which shares 2 of the 10 sample names by coincidence of subject matter, not root cause). GitGalaxy and tree-sitter are both correct; ctags is not wrong so much as structurally incapable of seeing these. Known, expected limitation of ctags' Haskell parser, now documented alongside its existing Haskell notes in tests/tools/ctags_reader.py -- not a GitHub issue, nothing in this repo to fix. @@ -840,7 +823,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `haskell` class existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 16 occurrences as of 2026-08-21T12:00:18Z* +*2-vs-1 -- 16 occurrences as of 2026-08-21T13:27:56Z* **Verdict** (by Claude Sonnet 5 (session investigation), 2026-08-19T00:00:00Z): > Not a real discrepancy -- structural tooling gap, already documented in the codebase. tests/tools/ctags_reader.py:39-40,228 sets CTAGS_CLASS_KINDS['haskell'] = set() on purpose: "ctags' Haskell parser has no class-shaped kind at all (constructor/function/module/type only)". Every example in this shape (data/newtype/class declarations -- ReaderOptions, CiteMethod, HasSyntaxExtensions, etc.) is real; ctags structurally cannot report any of them for this language, not a sample-specific miss. No action needed beyond this note. @@ -860,7 +843,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `haskell` function existence: GitGalaxy agree, tree-sitter, ctags differ -*2-vs-1 -- 2 occurrences as of 2026-08-21T12:00:18Z* +*2-vs-1 -- 2 occurrences as of 2026-08-21T13:27:56Z* **Verdict** (by Claude Sonnet 5 (session investigation), 2026-08-19T00:00:00Z): > Mixed shape, resolved by reading both of the 2 occurrences directly (no larger sample needed). (1) Options.hs:438 getExtensions -- real function, `instance HasSyntaxExtensions WriterOptions where getExtensions opts = writerExtensions opts`. A sibling instance for ReaderOptions at Options.hs:80 has the identical shape. Tree-sitter's Haskell grammar doesn't expose typeclass-instance-method clause bodies the way it does top-level bindings, and ctags' Haskell parser has no instance-method kind either -- GitGalaxy is correct, both other tools have a real recall gap on typeclass instance methods. (2) Shared.hs:475 extensionEnabled -- NOT a real function. Imported from Text.Pandoc.Extensions (Shared.hs:114), only ever appears as a guard-clause call (`| extensionEnabled Ext_gfm_auto_identifiers exts = ...`). GitGalaxy's regex misreads a guard-clause invocation as a definition -- genuine GitGalaxy false positive, worth its own engine bug against language_standards.py's haskell func_start rule. @@ -872,7 +855,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `haskell` function args: none agree, GitGalaxy, tree-sitter differ -*3-way split -- 9 occurrences as of 2026-08-21T12:00:18Z* +*3-way split -- 9 occurrences as of 2026-08-21T13:27:56Z* **Verdict** (by Claude Sonnet 5 (session investigation), 2026-08-19T00:00:00Z): > One systematic cause, confirmed by reading source for 3 of the 9 (getMetadataFromFiles App.hs:395-397, splitTextByIndices Shared.hs:142-143, tabFilter Shared.hs:256-259) and consistent with the shape of the remaining 6. Every case is a point-free/eta-reduced Haskell equation: the type signature declares N params, but the specific clause GitGalaxy and tree-sitter both align to only explicitly binds N-1 of them, handling the trailing argument via composition (`.`) or `\case`. GitGalaxy counts arity from the full type signature (the true logical arity); tree-sitter's declaration-only reading counts only the clause's explicitly-bound patterns (correct for that one equation, but undercounts true arity). Neither reader is wrong about what it's measuring -- same shape as Claim 1 in docs/why_gitgalaxy_beats_ast_here.md. GitGalaxy's answer is arguably the more useful coupling signal; recommend documenting as a candidate Claim rather than treating as an engine defect to fix toward matching tree-sitter. @@ -893,7 +876,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `java` function args: tree-sitter, ctags agree, GitGalaxy differ -*2-vs-1 -- 28 occurrences as of 2026-08-21T12:00:21Z* +*2-vs-1 -- 28 occurrences as of 2026-08-21T13:27:59Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`java/function/args/agree[ctags,tree_sitter]_vs[gitgalaxy]`) in `tri_comparison_ledger.json`. @@ -912,7 +895,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `java` function args: GitGalaxy, ctags agree, tree-sitter differ -*2-vs-1 -- 12 occurrences as of 2026-08-21T12:00:21Z* +*2-vs-1 -- 12 occurrences as of 2026-08-21T13:27:59Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`java/function/args/agree[ctags,gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. @@ -931,7 +914,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `java` function existence: tree-sitter, ctags agree, GitGalaxy differ -*2-vs-1 -- 3 occurrences as of 2026-08-21T12:00:21Z* +*2-vs-1 -- 3 occurrences as of 2026-08-21T13:27:59Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`java/function/existence/agree[ctags,tree_sitter]_vs[gitgalaxy]`) in `tri_comparison_ledger.json`. @@ -943,7 +926,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `java` function args: none agree, GitGalaxy, tree-sitter, ctags differ -*3-way split -- 1 occurrence as of 2026-08-21T12:00:21Z* +*3-way split -- 1 occurrence as of 2026-08-21T13:27:59Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`java/function/args/agree[none]_vs[ctags,gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -955,7 +938,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `javascript` function existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 266 occurrences as of 2026-08-21T12:00:24Z* +*2-vs-1 -- 266 occurrences as of 2026-08-21T13:28:01Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`javascript/function/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. @@ -974,7 +957,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `javascript` function existence: GitGalaxy agree, tree-sitter, ctags differ -*2-vs-1 -- 182 occurrences as of 2026-08-21T12:00:24Z* +*2-vs-1 -- 182 occurrences as of 2026-08-21T13:28:01Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`javascript/function/existence/agree[gitgalaxy]_vs[ctags,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -993,7 +976,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `javascript` function existence: ctags agree, GitGalaxy, tree-sitter differ -*2-vs-1 -- 150 occurrences as of 2026-08-21T12:00:24Z* +*2-vs-1 -- 150 occurrences as of 2026-08-21T13:28:01Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`javascript/function/existence/agree[ctags]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1012,7 +995,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `javascript` function existence: tree-sitter agree, GitGalaxy, ctags differ -*2-vs-1 -- 104 occurrences as of 2026-08-21T12:00:24Z* +*2-vs-1 -- 104 occurrences as of 2026-08-21T13:28:01Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`javascript/function/existence/agree[tree_sitter]_vs[ctags,gitgalaxy]`) in `tri_comparison_ledger.json`. @@ -1031,7 +1014,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `javascript` class existence: ctags agree, GitGalaxy, tree-sitter differ -*2-vs-1 -- 96 occurrences as of 2026-08-21T12:00:24Z* +*2-vs-1 -- 96 occurrences as of 2026-08-21T13:28:01Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`javascript/class/existence/agree[ctags]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1050,7 +1033,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `javascript` function existence: GitGalaxy, ctags agree, tree-sitter differ -*2-vs-1 -- 11 occurrences as of 2026-08-21T12:00:24Z* +*2-vs-1 -- 11 occurrences as of 2026-08-21T13:28:01Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`javascript/function/existence/agree[ctags,gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1069,7 +1052,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `javascript` function args: GitGalaxy, ctags agree, tree-sitter differ -*2-vs-1 -- 7 occurrences as of 2026-08-21T12:00:24Z* +*2-vs-1 -- 7 occurrences as of 2026-08-21T13:28:01Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`javascript/function/args/agree[ctags,gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1085,7 +1068,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `javascript` function args: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 2 occurrences as of 2026-08-21T12:00:24Z* +*2-vs-1 -- 2 occurrences as of 2026-08-21T13:28:01Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`javascript/function/args/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. @@ -1098,7 +1081,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `kotlin` function existence: ctags agree, GitGalaxy, tree-sitter differ -*2-vs-1 -- 15 occurrences as of 2026-08-21T12:00:27Z* +*2-vs-1 -- 15 occurrences as of 2026-08-21T13:28:04Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`kotlin/function/existence/agree[ctags]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1117,7 +1100,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `kotlin` class existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 3 occurrences as of 2026-08-21T12:00:27Z* +*2-vs-1 -- 3 occurrences as of 2026-08-21T13:28:04Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`kotlin/class/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. @@ -1129,7 +1112,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `kotlin` function existence: GitGalaxy agree, tree-sitter, ctags differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:00:27Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:28:04Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`kotlin/function/existence/agree[gitgalaxy]_vs[ctags,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1141,7 +1124,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `m4` function existence: ctags agree, GitGalaxy differ -*2-vs-1 -- 76 occurrences as of 2026-08-21T12:00:35Z* +*2-vs-1 -- 76 occurrences as of 2026-08-21T13:28:10Z* **Verdict** (by gemini-3.1-pro-high (agy), dispatched via tri-comparison-ledger-sweep, reviewed by claude-sonnet-5, 2026-08-20): > Clean, single-cause shape (all 10 sampled cases), not a GitGalaxy defect. Every sampled occurrence (curl/configure.ac lines 967-4994) is a real AC_DEFINE or AC_DEFINE_UNQUOTED call (e.g. line 2112: AC_DEFINE_UNQUOTED([CURL_DEFAULT_SSL_BACKEND], [...], [...])) -- an autoconf helper that emits a C preprocessor #define into the generated config.h at build time, NOT a new callable M4 macro definition. GitGalaxy's own func_start regex for m4 deliberately excludes AC_DEFINE/AC_DEFINE_UNQUOTED from its keyword set (m4_define|define|AC_DEFUN|AC_DEFUN_ONCE|AU_DEFUN|m4_defun only), so its silence here is correct. ctags' M4 parser heuristically tags any AC_DEFINE*-family call with a bracketed/plain first argument as a macro definition -- same macro-invocation-vs-definition confusion already documented for C's RICHCMP_WRAPPER pattern, now also documented in tests/tools/ctags_reader.py's m4 note. No GitHub issue against GitGalaxy -- this is a real, confirmed ctags-side limitation. (Separately, unrelated to this shape: a deeper live-pipeline recall gap causing GitGalaxy to extract only 1 m4 function total across the whole corpus, despite its func_start regex matching dozens of genuine AC_DEFUN/m4_define calls when run standalone, was found and fixed in part -- see PR #1927 for the func_start capture-group fix; the remaining pipeline-level gap is tracked separately, not part of this shape's verdict.) Investigated via gemini-3.1-pro-high (agy), all 10 sampled file:line citations independently verified. @@ -1161,7 +1144,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `m4` function existence: GitGalaxy agree, ctags differ -*2-vs-1 -- 36 occurrences as of 2026-08-21T12:00:35Z* +*2-vs-1 -- 36 occurrences as of 2026-08-21T13:28:10Z* **Verdict** (by claude-sonnet-5 (direct source read, no dispatch needed), 2026-08-20): > Confirmed real GitGalaxy false positive, now fixed. The old func_start regex had no capture group over the macro-name argument, so it matched the AC_DEFUN keyword itself as the 'function name' -- structurally identical to matching 'def' as a Python function's name instead of what follows it. gnucobol/configure.ac:658 'AC_DEFUN([AC_PROG_F77], [])' was reported as a function literally named 'AC_DEFUN'; ctags correctly reports nothing here since this call defines an empty macro body (a no-op placeholder, common autoconf idiom for stubbing out a check). Fixed in PR #1927: func_start now captures the real macro-name argument (AC_PROG_F77), handling m4's three real quoting conventions (backtick/apostrophe, bracket, double-bracket). Verified directly: the pipeline now reports 'AC_PROG_F77' at line 658, not 'AC_DEFUN'. @@ -1181,7 +1164,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `m4` class existence: GitGalaxy agree, ctags differ -*2-vs-1 -- 4 occurrences as of 2026-08-21T12:00:35Z* +*2-vs-1 -- 4 occurrences as of 2026-08-21T13:28:10Z* **Verdict** (by claude-sonnet-5 (direct source read, no dispatch needed), 2026-08-20): > Confirmed real GitGalaxy false positive, not yet fixed (tracked separately). m4's own class_start rule is explicitly None (m4 has no class/OOP concept) -- but detector.py's class extraction branch only checks _CLASS_START_NAMED_EXTRACTION_LANGS allowlist membership, not whether the language's own class_start is None, so m4 (and 18 other class_start=None languages) falls through to the generic 'class|struct|interface|trait|enum NAME' fallback regex regardless. That fallback has no awareness of m4 document structure, so it matches raw C struct declarations embedded as literal text inside autoconf feature-test macro arguments (e.g. curl/configure.ac:1358's 'struct SocketIFace *ISocket = NULL;' inside an AC_LANG_PROGRAM([[ ... ]]) block) as if they were real m4 classes. Verified directly against the live gatherer: gg_classes for curl/configure.ac returns ['SocketIFace', 'Library', 'sockaddr_in6'], none of which are real m4 constructs; ctags correctly reports none (no class-shaped kind for m4 at all). Filed as GitHub issue #1925 (broader architectural gap, confirmed for m4, 18 other class_start=None languages not yet checked) -- not fixed in this sweep. @@ -1197,7 +1180,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `makefile` function existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:00:36Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:28:11Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`makefile/function/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. @@ -1209,7 +1192,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `matlab` function args: none agree, GitGalaxy, tree-sitter differ -*3-way split -- 1 occurrence as of 2026-08-21T12:00:38Z* +*3-way split -- 1 occurrence as of 2026-08-21T13:28:13Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`matlab/function/args/agree[none]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1221,7 +1204,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `objective-c` function existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 104 occurrences as of 2026-08-21T12:00:40Z* +*2-vs-1 -- 104 occurrences as of 2026-08-21T13:28:14Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`objective-c/function/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. @@ -1240,7 +1223,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `objective-c` function existence: ctags agree, GitGalaxy, tree-sitter differ -*2-vs-1 -- 91 occurrences as of 2026-08-21T12:00:40Z* +*2-vs-1 -- 91 occurrences as of 2026-08-21T13:28:14Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`objective-c/function/existence/agree[ctags]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1259,7 +1242,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `objective-c` function existence: tree-sitter agree, GitGalaxy, ctags differ -*2-vs-1 -- 2 occurrences as of 2026-08-21T12:00:40Z* +*2-vs-1 -- 2 occurrences as of 2026-08-21T13:28:14Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`objective-c/function/existence/agree[tree_sitter]_vs[ctags,gitgalaxy]`) in `tri_comparison_ledger.json`. @@ -1270,7 +1253,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `objective-c` function existence: GitGalaxy agree, tree-sitter, ctags differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:00:40Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:28:14Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`objective-c/function/existence/agree[gitgalaxy]_vs[ctags,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1282,7 +1265,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `perl` function existence: tree-sitter agree, GitGalaxy, ctags differ -*2-vs-1 -- 122 occurrences as of 2026-08-21T12:00:46Z* +*2-vs-1 -- 122 occurrences as of 2026-08-21T13:28:20Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`perl/function/existence/agree[tree_sitter]_vs[ctags,gitgalaxy]`) in `tri_comparison_ledger.json`. @@ -1301,7 +1284,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `perl` function existence: ctags agree, GitGalaxy, tree-sitter differ -*2-vs-1 -- 7 occurrences as of 2026-08-21T12:00:46Z* +*2-vs-1 -- 7 occurrences as of 2026-08-21T13:28:20Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`perl/function/existence/agree[ctags]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1317,7 +1300,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `perl` function existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 7 occurrences as of 2026-08-21T12:00:46Z* +*2-vs-1 -- 7 occurrences as of 2026-08-21T13:28:20Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`perl/function/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. @@ -1333,7 +1316,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `perl` class existence: GitGalaxy, ctags agree, tree-sitter differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:00:46Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:28:20Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`perl/class/existence/agree[ctags,gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1343,7 +1326,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `perl` function existence: GitGalaxy agree, tree-sitter, ctags differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:00:46Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:28:20Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`perl/function/existence/agree[gitgalaxy]_vs[ctags,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1353,7 +1336,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `perl` function args: none agree, GitGalaxy, tree-sitter differ -*3-way split -- 64 occurrences as of 2026-08-21T12:00:46Z* +*3-way split -- 64 occurrences as of 2026-08-21T13:28:20Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`perl/function/args/agree[none]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1374,7 +1357,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `php` class existence: ctags agree, GitGalaxy, tree-sitter differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:00:53Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:28:25Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`php/class/existence/agree[ctags]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1384,7 +1367,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `php` function existence: GitGalaxy, ctags agree, tree-sitter differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:00:53Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:28:25Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`php/function/existence/agree[ctags,gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1396,7 +1379,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `powershell` function existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 16 occurrences as of 2026-08-21T12:00:57Z* +*2-vs-1 -- 16 occurrences as of 2026-08-21T13:28:27Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`powershell/function/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. @@ -1415,7 +1398,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `powershell` class existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 7 occurrences as of 2026-08-21T12:00:57Z* +*2-vs-1 -- 7 occurrences as of 2026-08-21T13:28:27Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`powershell/class/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. @@ -1431,7 +1414,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `powershell` function existence: GitGalaxy, ctags agree, tree-sitter differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:00:57Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:28:27Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`powershell/function/existence/agree[ctags,gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1441,7 +1424,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `powershell` function args: none agree, GitGalaxy, tree-sitter differ -*3-way split -- 5 occurrences as of 2026-08-21T12:00:57Z* +*3-way split -- 5 occurrences as of 2026-08-21T13:28:27Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`powershell/function/args/agree[none]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1457,7 +1440,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `python` function existence: GitGalaxy, ctags agree, tree-sitter differ -*2-vs-1 -- 100 occurrences as of 2026-08-21T12:01:08Z* +*2-vs-1 -- 100 occurrences as of 2026-08-21T13:28:36Z* **Verdict** (by claude sonnet 5, tri-comparison-ledger-sweep (direct investigation, no dispatch needed), 2026-08-21T12:03:03Z): > Already documented as Claim 2 in docs/why_gitgalaxy_beats_ast_here.md: tree-sitter-python has no concept of Cython's cdef class/cdef/cpdef syntax at all and loses track of scope at each cdef class boundary, so it finds 0 functions in cython/MemoryView.pyx and cython/MemoryView.pxd (0/0 vs GitGalaxy+ctags' 72/16, full agreement as of the 2026-08-21 get_slice_from_memview follow-up fix -- see the sibling agree[ctags]_vs[gitgalaxy,tree_sitter] shape's verdict for that fix's details). This shape's count grew from 32 to 99 to 100 across this PR's two fixes: it originally covered only the 32 'def'-based methods inside cdef class blocks; each cdef/cpdef func_start fix moved newly-recognized occurrences into THIS shape too, since they still disagree with tree-sitter for the identical underlying reason. GitGalaxy now has zero recall gaps on this corpus for Cython functions -- the only remaining disagreement with tree-sitter is tree-sitter's own structural blindness to the Cython dialect, not a GitGalaxy defect. No GitGalaxy fix needed for tree-sitter's own recall here -- grammar limitation, not an engine defect. @@ -1477,7 +1460,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `python` class existence: GitGalaxy, ctags agree, tree-sitter differ -*2-vs-1 -- 4 occurrences as of 2026-08-21T12:01:08Z* +*2-vs-1 -- 4 occurrences as of 2026-08-21T13:28:36Z* **Verdict** (by claude sonnet 5, tri-comparison-ledger-sweep (direct investigation, no dispatch needed), 2026-08-21T03:23:52Z): > Extends Claim 2 (docs/why_gitgalaxy_beats_ast_here.md) one syntactic level up: tree-sitter-python doesn't just lose track of scope inside a cdef class block, it fails to recognize the 'cdef class' declaration itself as a class at all -- 0 class nodes reported for cython/MemoryView.pyx, missing all 4 real classes (array, Enum, memoryview, _memoryviewslice). GitGalaxy's class_start regex and ctags both correctly identify all 4 by name, confirmed via direct gather_language() check. Note: GitGalaxy's own class_data schema has no start_line column (documented in tri_comparison_gatherer.py's own module docstring), so the ledger's stored example shows a None 'reading' for GitGalaxy on this shape -- that's the (structurally absent) line number field, not an indication GitGalaxy missed the class; by NAME it matches ctags exactly. No GitGalaxy fix needed -- tree-sitter-python grammar limitation. docs/why_gitgalaxy_beats_ast_here.md's Claim 2 updated with this class-level evidence in the same PR. @@ -1493,7 +1476,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `ruby` class existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 6 occurrences as of 2026-08-21T12:01:10Z* +*2-vs-1 -- 6 occurrences as of 2026-08-21T13:28:37Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`ruby/class/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. @@ -1508,7 +1491,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `ruby` function args: tree-sitter, ctags agree, GitGalaxy differ -*2-vs-1 -- 6 occurrences as of 2026-08-21T12:01:10Z* +*2-vs-1 -- 6 occurrences as of 2026-08-21T13:28:37Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`ruby/function/args/agree[ctags,tree_sitter]_vs[gitgalaxy]`) in `tri_comparison_ledger.json`. @@ -1523,7 +1506,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `ruby` function args: GitGalaxy, ctags agree, tree-sitter differ -*2-vs-1 -- 3 occurrences as of 2026-08-21T12:01:10Z* +*2-vs-1 -- 3 occurrences as of 2026-08-21T13:28:37Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`ruby/function/args/agree[ctags,gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1535,7 +1518,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `ruby` class existence: ctags agree, GitGalaxy, tree-sitter differ -*2-vs-1 -- 2 occurrences as of 2026-08-21T12:01:10Z* +*2-vs-1 -- 2 occurrences as of 2026-08-21T13:28:37Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`ruby/class/existence/agree[ctags]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1548,7 +1531,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `rust` function existence: GitGalaxy agree, tree-sitter, ctags differ -*2-vs-1 -- 152 occurrences as of 2026-08-21T12:01:14Z* +*2-vs-1 -- 152 occurrences as of 2026-08-21T13:28:41Z* **Verdict** (by Claude Sonnet 5 (resolved from existing Claim 6 documentation, no dispatch), 2026-08-19T00:00:00Z): > Not a new question -- already-documented, evidence-backed rust behavior (Claim 6, docs/why_gitgalaxy_beats_ast_here.md: 'structure recall inside opaque macro bodies'). Confirmed directly: all 5 sampled names (get_param, init_access, get_components, from_components, apply) are in bevy/bevy_ecs_macros.rs, inside a `quote! { ... }` proc-macro body (confirmed at source lines 444-460 -- `#path`/`#fields_alias` interpolation syntax is the classic quote! token-generation pattern). These are real Rust function definitions being code-generated by a proc macro; GitGalaxy's regex correctly parses real function syntax wherever it textually appears, including inside macro bodies. tree-sitter-rust and ctags' Rust parser both treat macro_rules!/macro-invocation bodies as opaque token trees and structurally cannot emit function nodes for anything inside one -- not a bug in either, a real grammar limitation. This is exactly why rust is one of the 3 languages (with csharp/fortran) already promoted into ground truth via blind-spot-region detection in the OLD bi-comparison tool (tree_sitter_accuracy_audit.py's _find_blind_spot_ranges) -- this tri-comparison ledger entry is that same, already-understood gap surfacing again under the new 3-tool reconciliation. GitGalaxy is correct; no engine defect, no issue needed. Resolved directly from existing documentation, no fresh dispatch required (tri-comparison-ledger-sweep skill step 1.3). @@ -1568,7 +1551,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `rust` class existence: GitGalaxy agree, tree-sitter, ctags differ -*2-vs-1 -- 25 occurrences as of 2026-08-21T12:01:14Z* +*2-vs-1 -- 25 occurrences as of 2026-08-21T13:28:41Z* **Verdict** (by Gemini (dispatched via tri-comparison-ledger-sweep), confirmed by Claude Sonnet 5, 2026-08-19T00:00:00Z): > Same mechanism as the already-resolved rust/function/existence/agree[gitgalaxy]_vs[ctags,tree_sitter] shape (Claim 6, docs/why_gitgalaxy_beats_ast_here.md) -- extended from `fn` definitions inside `quote!{}` invocation bodies to `struct` definitions inside `macro_rules!` DEFINITION bodies. All 6 sampled names confirmed, independently re-verified against source (not just the dispatched agent's own read): NonZeroVisitor (line 90), SaturatingVisitor (112), PrimitiveVisitor (136) inside serde/serde_core_de_impls.rs's `impl_deserialize_num!` macro (def starts line 81); SeqVisitor (998), SeqInPlaceVisitor (1036) inside `seq_impl!` (def starts 978); TupleVisitor (1403) inside `tuple_impl_body!` (nested in `tuple_impls!`, def starts 1396). All 6 are real, complete `struct` declarations, each immediately followed by a genuine `impl<'de,...> Visitor<'de> for ` block -- generated once per macro invocation, not fragments or hallucinated matches. tree-sitter and ctags both treat a macro_rules! arm's body as an opaque, unexpanded token tree and structurally cannot emit struct nodes from inside one, for the identical reason they can't see function definitions inside quote!{} bodies. GitGalaxy is correct in all 6 sampled cases; judged (not independently re-confirmed beyond the sample) to generalize to the full 25, all same-shaped serde-crate occurrences. No new tool defect -- Claim 6's doc text already covered this generically (`struct_item` was already named) but had no concrete cited example for this specific shape; added one (docs/why_gitgalaxy_beats_ast_here.md) rather than filing an issue. @@ -1588,7 +1571,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `rust` function args: tree-sitter, ctags agree, GitGalaxy differ -*2-vs-1 -- 21 occurrences as of 2026-08-21T12:01:14Z* +*2-vs-1 -- 21 occurrences as of 2026-08-21T13:28:41Z* **Verdict** (by Gemini (dispatched via tri-comparison-ledger-sweep, 2 rounds with self-correction), confirmed by Claude Sonnet 5, 2026-08-19T00:00:00Z): > Confirmed GitGalaxy engine defect, same root cause as the sibling shape rust/function/args/agree[none]_vs[gitgalaxy,tree_sitter] (#1872): a Rust lifetime tick (`'_`, `'a`, `'static`) never gets recognized as non-string during bracket/quote scanning. This shape surfaces the SECOND manifestation, in a different function than the first: `_matching_paren_end` (gitgalaxy/core/detector.py:3675-3703) has NO lifetime guard at all (unlike _count_top_level_args's broken-but-present one). A lifetime tick makes its self-containment check falsely fail, falling through to the comma/whitespace-split fallback meant for Lisp/Scheme/Shell (~line 4296) -- for single-parameter signatures with a lifetime and no comma this OVER-counts (opposite direction from the sibling shape's under-count), for multi-param signatures it under-counts via the same swallowed-closing-paren mechanism. Extends the how_to_investigate_a_discrepancy.md worked example (bevy_ecs_table.rs::initialize, 5 real params, GitGalaxy reports 3) across the full 8-item sample, independently hand-traced and confirmed exact-match against real source for all 8: bevy_ecs_table.rs:171,194, bevy_ecs_world.rs:2969,3005, serde_internals_ast.rs:62 (under-count, multi-param); bevy_reflect_path.rs:43, serde_core_de_impls.rs:3147, serde_internals_ast.rs:119 (over-count, single-param via the whitespace-split fallback). Dispatched investigation initially produced a fabricated mechanism on its first pass; caught by the dispatching agent's own manual code trace, corrected on a second pass, then independently re-verified byte-for-byte against all 8 real signatures before being accepted here -- treat this as a genuinely double-checked finding, not a single-pass claim. ctags and tree-sitter are both correct in every case. Judged to plausibly explain most/all of the remaining 21 (any rust signature with a lifetime annotation is susceptible) and possibly under-reported beyond this specific ledger shape too, since lifetimes are extremely common idiomatic rust. Added as a follow-up comment on #1872 rather than a duplicate issue, since both bugs should be fixed together. @@ -1608,7 +1591,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `rust` class existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 3 occurrences as of 2026-08-21T12:01:14Z* +*2-vs-1 -- 3 occurrences as of 2026-08-21T13:28:41Z* **Verdict** (by Claude Sonnet 5 (resolved directly via live ctags run, no dispatch), 2026-08-19T00:00:00Z): > Confirmed structural ctags limitation, not a bug -- resolved directly (no dispatch needed). All 3 sampled names (XRegUnion, FRegUnion, VRegUnion) are real Rust `union { }` declarations (confirmed at wasmtime/wasmtime_pulley_interp.rs:404,529,604), distinct from `struct` -- Rust's less-common C-style unsafe union construct. Ran `ctags --list-kinds-full=Rust` directly: its Rust parser's kind list is macro/method/implementation/enumerator/function/enum/interface/field/module/struct/typedef/variable -- there is NO union kind at all. Confirmed via direct ctags run against this exact file: it correctly finds the wrapping `struct FRegVal(FRegUnion)`-shaped types right next to each missed union, so this isn't a general miss, specifically a missing Rust-union kind. Same category as the already-documented ctags Haskell class-kind gap (tests/tools/ctags_reader.py) -- worth a similar doc note there, not a GitHub issue (nothing to fix, ctags upstream has no union support for this language). @@ -1621,7 +1604,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `rust` function existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:01:14Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:28:41Z* **Verdict** (by Claude Sonnet 5 (resolved directly via live ctags run, no dispatch), 2026-08-19T00:00:00Z): > Confirmed via direct ctags run and sibling comparison, resolved directly (no dispatch needed). `done_decode` (wasmtime/wasmtime_pulley_interp.rs:964) has a destructuring-pattern parameter -- `Done { _priv }: Done`, not a simple `name: Type` binding. Ran ctags directly against the file: its IMMEDIATE SIBLING in the same impl block, `debug_assert_done_reason_none` (line 960, same visibility/receiver shape, ordinary `&mut self`-only signature), IS correctly found as a ctags 'method'. done_decode alone is missing from ctags' output. Isolates the cause precisely to the destructuring-pattern parameter -- ctags' regex-based Rust parser appears to fail/skip the whole function when a parameter is a struct pattern rather than a plain identifier binding. GitGalaxy and tree-sitter both handle this fine (both agree on line 964). N=1 in this corpus, plausibly a real, narrow ctags parser gap (not GitGalaxy's) -- not chasing further given the tiny sample, noting rather than filing an issue since there's nothing in this repo to fix. @@ -1632,7 +1615,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `rust` function args: none agree, GitGalaxy, tree-sitter differ -*3-way split -- 21 occurrences as of 2026-08-21T12:01:14Z* +*3-way split -- 21 occurrences as of 2026-08-21T13:28:41Z* **Verdict** (by Gemini (dispatched via tri-comparison-ledger-sweep), confirmed by Claude Sonnet 5, 2026-08-19T00:00:00Z): > Confirmed GitGalaxy engine defect, not a modeling disagreement -- tree-sitter is correct in all 8 sampled cases (and this generalizes to the full 21: every sampled name is a deserialize_*/spawn_*_caller-shaped signature carrying a rust lifetime annotation, the exact trigger). Root cause, independently confirmed via two methods (dispatched agent read the code path; a second grep pass confirmed the attribute is dead): `gitgalaxy/core/detector.py::StructuralExtractor._count_top_level_args` has a guard meant to exempt rust/scala lifetime marks (`'_`, `'static`) from its string-literal scanner -- `getattr(self, 'language', '') in ('rust', 'scala')` around line 3766 -- but the class stores the language as `self.primary_lang_id` (set at line 497), never `self.language`. `self.language` is referenced NOWHERE ELSE in the file, confirmed by grep. The getattr always silently falls back to `''`, so the exemption guard never fires for any language, ever -- every lifetime `'` gets treated as an unterminated string-literal opener, swallowing all subsequent top-level commas until a real closing quote or end-of-string, fusing 2+ parameters into 1. A signature with 3 lifetime marks (odd count) never exits string mode at all and undercounts every remaining parameter. Real signatures confirmed at source: bevy/bevy_ecs_world.rs:1106,1121,1270 (`MovingPtr<'_, B>` swallows the next comma, 3 vs real 4, or 2 vs real 3); serde/serde_core_de_mod.rs:1105,1115 (`&'static str` swallows the next comma, 2 vs real 3); serde_core_de_mod.rs:1136 (two lifetimes, both trailing commas swallowed, 2 vs real 4); serde_core_de_mod.rs:1152,1163 (three lifetime marks, odd count means string mode never exits, 2 vs real 4). ctags has null coverage for these specific occurrences because they're bodyless trait-method declarations (ending in `;` inside a `trait` block) -- unrelated to the args bug, ctags appears to skip signature-only declarations generally. Filed as its own GitHub issue (attribute-name mismatch, one-line fix: `self.language` -> `self.primary_lang_id`, or equivalent), separate from this ledger record. @@ -1654,7 +1637,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `scala` function args: none agree, GitGalaxy, tree-sitter differ -*3-way split -- 16 occurrences as of 2026-08-21T12:01:17Z* +*3-way split -- 16 occurrences as of 2026-08-21T13:28:43Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`scala/function/args/agree[none]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1675,7 +1658,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `scheme` function existence: GitGalaxy agree, ctags differ -*2-vs-1 -- 50 occurrences as of 2026-08-21T12:01:21Z* +*2-vs-1 -- 50 occurrences as of 2026-08-21T13:28:48Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`scheme/function/existence/agree[gitgalaxy]_vs[ctags]`) in `tri_comparison_ledger.json`. @@ -1694,7 +1677,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ✅ `scheme` function existence: ctags agree, GitGalaxy differ -*2-vs-1 -- 84 occurrences as of 2026-08-21T12:01:21Z* +*2-vs-1 -- 84 occurrences as of 2026-08-21T13:28:48Z* **Verdict** (by gemini-3.1-pro-high (agy), dispatched via tri-comparison-ledger-sweep, reviewed and fixed by claude-sonnet-5, 2026-08-20): > Confirmed real, catastrophic GitGalaxy engine defect, generalizes to the full 92 occurrences (and beyond -- this was a 100% recall drop for the whole language, not specific to the sampled cases). Root cause isolated to detector.py's StructuralExtractor._slice_by_braces (Integration Mode B): its scope-delimiter selection checked `lang_id == "lisp"` to choose parenthesis delimiters over the curly-brace default -- but "lisp" has never been a real key in LANGUAGE_DEFINITIONS (only "scheme" is), so that branch was unreachable dead code in production. Every real scheme file fell through to the curly-brace default; since scheme is entirely parenthesis-delimited, the downstream scope-body search never found an opener and silently discarded every func_start match. GitGalaxy's own func_start regex was never the problem -- confirmed matching correctly standalone (31/31 hits on one file) and prism.py's comment stripping confirmed clean (raw (define count unchanged pre/post-prism). Fixed: delimiter choice now keys off lexical_family ("recursive_block_lisp") instead of the dead lang_id string, verified directly against the gatherer (0 -> 58 real functions found; ctags finds 92, so a smaller residual recall gap remains for a future pass, tracked as a follow-on, not blocking this fix). Filed as GitHub issue #1928. A pre-existing unit test (test_detector_mode_b_lisp_family) had been passing for the wrong reason (its mock language was literally named "lisp", matching the dead string check by construction) -- corrected to use scheme's real lexical_family value so it now validates the actual production mechanism. Investigated via gemini-3.1-pro-high (agy): live-pipeline isolation with a monkey-patch before/after proof (0 -> 14 functions when lang_id coerced to match the old check), independently re-verified by Claude against the exact cited source lines before applying. @@ -1716,7 +1699,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `shell` function existence: ctags agree, GitGalaxy, tree-sitter differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:01:23Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:28:49Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`shell/function/existence/agree[ctags]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1728,7 +1711,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `solidity` function existence: GitGalaxy agree, tree-sitter differ -*2-vs-1 -- 6 occurrences as of 2026-08-21T12:01:24Z* +*2-vs-1 -- 6 occurrences as of 2026-08-21T13:28:50Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`solidity/function/existence/agree[gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1745,7 +1728,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `swift` function existence: GitGalaxy agree, tree-sitter differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:01:26Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:28:52Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`swift/function/existence/agree[gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1755,7 +1738,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `swift` function existence: tree-sitter agree, GitGalaxy differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:01:26Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:28:52Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`swift/function/existence/agree[tree_sitter]_vs[gitgalaxy]`) in `tri_comparison_ledger.json`. @@ -1765,7 +1748,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `swift` function args: none agree, GitGalaxy, tree-sitter differ -*3-way split -- 1 occurrence as of 2026-08-21T12:01:26Z* +*3-way split -- 1 occurrence as of 2026-08-21T13:28:52Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`swift/function/args/agree[none]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1777,7 +1760,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `tcl` function existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 4 occurrences as of 2026-08-21T12:01:28Z* +*2-vs-1 -- 4 occurrences as of 2026-08-21T13:28:53Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`tcl/function/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. @@ -1790,7 +1773,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `tcl` function existence: tree-sitter, ctags agree, GitGalaxy differ -*2-vs-1 -- 2 occurrences as of 2026-08-21T12:01:28Z* +*2-vs-1 -- 2 occurrences as of 2026-08-21T13:28:53Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`tcl/function/existence/agree[ctags,tree_sitter]_vs[gitgalaxy]`) in `tri_comparison_ledger.json`. @@ -1801,7 +1784,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `tcl` function existence: GitGalaxy, ctags agree, tree-sitter differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:01:28Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:28:53Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`tcl/function/existence/agree[ctags,gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1811,7 +1794,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `tcl` function existence: GitGalaxy agree, tree-sitter, ctags differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:01:28Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:28:53Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`tcl/function/existence/agree[gitgalaxy]_vs[ctags,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1823,7 +1806,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `typescript` function existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 1907 occurrences as of 2026-08-21T12:01:49Z* +*2-vs-1 -- 1907 occurrences as of 2026-08-21T13:29:14Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`typescript/function/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. @@ -1842,7 +1825,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `typescript` class existence: GitGalaxy, tree-sitter agree, ctags differ -*2-vs-1 -- 501 occurrences as of 2026-08-21T12:01:49Z* +*2-vs-1 -- 501 occurrences as of 2026-08-21T13:29:14Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`typescript/class/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`) in `tri_comparison_ledger.json`. @@ -1861,7 +1844,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `typescript` function existence: tree-sitter agree, GitGalaxy, ctags differ -*2-vs-1 -- 174 occurrences as of 2026-08-21T12:01:49Z* +*2-vs-1 -- 174 occurrences as of 2026-08-21T13:29:14Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`typescript/function/existence/agree[tree_sitter]_vs[ctags,gitgalaxy]`) in `tri_comparison_ledger.json`. @@ -1880,7 +1863,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `typescript` function existence: ctags agree, GitGalaxy, tree-sitter differ -*2-vs-1 -- 61 occurrences as of 2026-08-21T12:01:49Z* +*2-vs-1 -- 61 occurrences as of 2026-08-21T13:29:14Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`typescript/function/existence/agree[ctags]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1899,7 +1882,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `typescript` function existence: tree-sitter, ctags agree, GitGalaxy differ -*2-vs-1 -- 9 occurrences as of 2026-08-21T12:01:49Z* +*2-vs-1 -- 9 occurrences as of 2026-08-21T13:29:14Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`typescript/function/existence/agree[ctags,tree_sitter]_vs[gitgalaxy]`) in `tri_comparison_ledger.json`. @@ -1917,7 +1900,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `typescript` class existence: ctags agree, GitGalaxy, tree-sitter differ -*2-vs-1 -- 2 occurrences as of 2026-08-21T12:01:49Z* +*2-vs-1 -- 2 occurrences as of 2026-08-21T13:29:14Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`typescript/class/existence/agree[ctags]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1928,7 +1911,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `typescript` function existence: GitGalaxy agree, tree-sitter, ctags differ -*2-vs-1 -- 2 occurrences as of 2026-08-21T12:01:49Z* +*2-vs-1 -- 2 occurrences as of 2026-08-21T13:29:14Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`typescript/function/existence/agree[gitgalaxy]_vs[ctags,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1939,7 +1922,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `typescript` function args: none agree, GitGalaxy, tree-sitter differ -*3-way split -- 4 occurrences as of 2026-08-21T12:01:49Z* +*3-way split -- 4 occurrences as of 2026-08-21T13:29:14Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`typescript/function/args/agree[none]_vs[gitgalaxy,tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1954,7 +1937,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `zig` class existence: tree-sitter agree, GitGalaxy differ -*2-vs-1 -- 10 occurrences as of 2026-08-21T12:01:58Z* +*2-vs-1 -- 10 occurrences as of 2026-08-21T13:29:22Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`zig/class/existence/agree[tree_sitter]_vs[gitgalaxy]`) in `tri_comparison_ledger.json`. @@ -1973,7 +1956,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `zig` class existence: GitGalaxy agree, tree-sitter differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:01:58Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:29:22Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`zig/class/existence/agree[gitgalaxy]_vs[tree_sitter]`) in `tri_comparison_ledger.json`. @@ -1983,7 +1966,7 @@ Sorted 2-vs-1 splits before 3-way splits, unvalidated before validated, biggest ### ❓ `zig` function existence: tree-sitter agree, GitGalaxy differ -*2-vs-1 -- 1 occurrence as of 2026-08-21T12:01:58Z* +*2-vs-1 -- 1 occurrence as of 2026-08-21T13:29:22Z* **Not yet investigated.** See `docs/self_scan/how_to_investigate_a_discrepancy.md` for the process -- read the source at a few examples below, then hand-edit this entry (`zig/function/existence/agree[tree_sitter]_vs[gitgalaxy]`) in `tri_comparison_ledger.json`. diff --git a/tests/tools/ctags_reader.py b/tests/tools/ctags_reader.py index 478cb413..e5df8c1e 100644 --- a/tests/tools/ctags_reader.py +++ b/tests/tools/ctags_reader.py @@ -110,6 +110,42 @@ `AC_DEFINE`/`AC_DEFINE_UNQUOTED` calls, zero genuine `AC_DEFUN`/`m4_define` misses) via `m4/function/existence/agree[ctags]_vs[gitgalaxy]` (79 occurrences total) -- a real ctags limitation, not a GitGalaxy defect. + - cpp: same macro-invocation-vs-definition confusion as C's RICHCMP_WRAPPER note above, in + two distinct shapes, both real ctags limitations, neither a GitGalaxy or tree-sitter + defect. (1) A macro used as a RETURN-TYPE PREFIX before the real function name: Windows + COM's `IFACEMETHODIMP_(void) FancyZones::Run() noexcept {...}` + (powertoys/FancyZones.cpp:213) -- ctags tags the macro invocation `IFACEMETHODIMP_(void)` + itself as a complete function (name `IFACEMETHODIMP_`, signature `(void)`) and then reads + the REAL name `FancyZones::Run` that follows as body content, missing it entirely. Same + shape for godot/rendering_server_default.h's `FUNC2`/`FUNC3`/`FUNCRIDTEX1` macros (each + expands to a full method declaration at its call site, but ctags tags the macro call + itself) and powertoys/ImageResizerExt.cpp's `__control_entrypoint`. (2) A macro DEFINITION + BODY containing what looks like a complete function declarator, tagged as if it were real, + already-expanded code: godot/object.h's `GDCLASS`/`_FORCE_INLINE_`-based macros + (`#define GDCLASS(m_class, m_inherits) ... _FORCE_INLINE_ bool (Object::*_get_get() const) + (...) {...} ...`) never actually run as written -- they only produce real code once + expanded at a `GDCLASS(SomeClass, Base)` call site elsewhere -- but ctags parses inside the + `#define` body itself and tags `_get_get`/`_get_set`/`_get_bind_methods`/etc. as if they + were ordinary member functions. Investigated via + `cpp/function/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]` (1097 occurrences, + 2026-08-21) -- the overwhelming majority of that shape was actually a + qualification/pattern-truncation gap in THIS reader (see `_QUALIFY_NAME_WITH_SCOPE`/ + `--pattern-length-limit=0` below), fixed directly; these two macro-parsing shapes are the + genuine remainder. + Separately (class-side, not function): ctags' "g" (enum) kind was entirely absent from + `CTAGS_CLASS_KINDS["cpp"]` (unlike C's, which already had it) -- `enum class`/`enum struct` + (C++11 scoped enums) are real GitGalaxy class_start matches with no ctags counterpart at + all until this map included "g" too (gated on the source line itself distinguishing scoped + from unscoped enums, since ctags' own "g" kind doesn't -- see `_is_cpp_unscoped_enum`). + Investigated via `cpp/class/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]` (95 + occurrences, 2026-08-21) -- a bug in this test harness (mirroring C's own pre-2026-08-19 + gap above), not in ctags, GitGalaxy, or tree-sitter. A separate, smaller finding from the + same investigation is a real GitGalaxy defect, not a ctags one: `class Foo;` forward + declarations are counted as real classes by both GitGalaxy's `class_start` regex and this + module's own tree-sitter walker (fixed here -- see `_walk_tree_sitter`'s docstring) but + NOT by ctags, which correctly excludes them -- filed separately since the production + engine's fix needs care around C++ multiple inheritance, see the GitHub issue referenced in + tri_comparison_ledger.json's corresponding entry. Cross-reference gitgalaxy/standards/language_standards.py's own class_start/func_start definitions before ever widening one of these maps -- do not add a kind because its letter looks right. @@ -163,6 +199,7 @@ from __future__ import annotations import functools +import re import shutil import subprocess from dataclasses import dataclass @@ -295,8 +332,23 @@ def has_ctags() -> bool: # `ctags -x` run against sqlite/lemon.c and others), this map was just dropping them before # reconciliation ever saw them -- a bug in this test harness, not in ctags, GitGalaxy, or # tree-sitter. - "cpp": {"c", "s"}, # class, struct - "csharp": {"c", "s", "i"}, # class, struct, interface + "cpp": {"c", "s", "u", "g"}, # class, struct, union, enum (enum gated below -- see + # _is_cpp_unscoped_enum: ctags' "g" kind covers BOTH `enum class Foo` and plain, unscoped + # `enum Foo`, but GitGalaxy's own cpp class_start regex only counts the SCOPED form + # (enum[ \t\n]+class|enum[ \t\n]+struct, gitgalaxy/standards/language_standards.py) -- + # unlike C, where GitGalaxy counts every enum unconditionally (see the "c" entry above) since + # C has no scoped-enum concept to distinguish from. Confirmed via + # cpp/class/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]: union (MTFlag/MTNumeric, + # godot/node.h) and enum class (AncestralClass/EditorExitKind/HotkeyId/OpType/SpecialMode/ + # toast_notification_handler_result) were both simply absent from this map, matching C's + # same pre-2026-08-19 gap (9 occurrences) before it was fixed there. + "csharp": {"c", "s", "i", "g"}, # class, struct, interface, enum -- matches GitGalaxy's own + # csharp class_start regex (class|interface|struct|record(?:\s+(?:struct|class))?|enum, + # gitgalaxy/standards/language_standards.py). Found via the same incidental-finding pass that + # fixed cpp's identical gap (2026-08-21, cpp/class/existence sweep) -- "g" (enum) was simply + # absent from this map too. Unlike C++'s enum, C# has no scoped-vs-unscoped distinction to + # gate on (every `enum Foo {...}` is equally a real type), so this is a plain, unconditional + # addition -- no source-text gate needed the way cpp's `_is_cpp_unscoped_enum` requires. "css": {"c"}, # CSS "class" kind is a literal .class selector -- matches GitGalaxy's own # css class_start intent (it also targets selector-like entities) "fortran": {"t"}, # derived types and structures @@ -370,6 +422,80 @@ def ctags_available_for_functions(lang: str) -> bool: return bool(CTAGS_FUNC_KINDS.get(lang)) +# ctags' "g" (enum) kind tags both `enum class Foo {...}` and plain `enum Foo {...}` identically +# (confirmed: neither the tag's kind letter nor any extension field distinguishes them -- checked +# with --fields=+z too), so telling them apart requires reading the tag's own verbatim matched +# source line, the same trick _QUALIFY_NAME_WITH_SCOPE already uses below. +_CPP_SCOPED_ENUM_RE = re.compile(r"\benum[ \t]+(?:class|struct)\b") + + +def _is_cpp_unscoped_enum(kind: str, source_text: str) -> bool: + return kind == "g" and not _CPP_SCOPED_ENUM_RE.search(source_text) + + +# ctags' scope field ("s", on by default) emits `:` in the extension-fields +# trailer -- e.g. `class:Object::Connection` for a method nested in namespace Object, class +# Connection. Only one of these keys is ever present per tag (whichever kind actually encloses +# it); checked in this order for no particular reason beyond determinism. +_CTAGS_SCOPE_KIND_KEYS = ("class", "struct", "namespace", "union", "enum", "interface", "function") + +# Languages where GitGalaxy's and tree-sitter's own function/class name already bakes the +# enclosing scope into the name for an OUT-OF-CLASS definition, because that source syntax spells +# it out explicitly (C++'s `ReturnType ClassName::method(...)` convention -- both tools just read +# the qualified identifier straight out of the source text). ctags instead splits this into a bare +# `name` field plus a separate scope field -- and, critically, emits that SAME scope field for an +# ordinary IN-CLASS-BODY method too (`class Foo { void bar() {...} }`), where GitGalaxy/tree-sitter +# read the bare, unqualified name because that's genuinely all the source says. ctags' own tag data +# can't tell these two cases apart (confirmed: both `class Foo { void bar() }` and +# `void Foo::bar()` produce the identical `name:bar / class:Foo` tag shape) -- so qualification +# below is gated on actually finding the literal `Scope::name` text in the tag's own verbatim +# matched source line, not applied unconditionally. Confirmed via +# cpp/function/existence/agree[gitgalaxy,tree_sitter]_vs[ctags] (1097 occurrences) -- +# NVDA/storage.cpp alone has 62 methods, all out-of-class definitions, where all three tools found +# the exact same definition at the exact same line; re-joining name+scope this way (with the +# source-line guard) resolves 969/1015 (95%) of the qualified-name occurrences corpus-wide without +# regressing any in-class-body method. +# Deliberately NOT applied to every ctags language: most (python, java, csharp, ...) never write +# an out-of-class qualified definition at all, so this path is simply inert for them. If a similar +# convention turns up for another language's ledger shapes later, add it here rather than assuming +# this set is complete. +_QUALIFY_NAME_WITH_SCOPE = {"cpp"} + +# ctags' scope VALUE for a member of a class nested inside an outer namespace includes that +# outer namespace as its own leading segment (`tensorflow::MlirOptimizationPassRegistry`, +# `__anon50f1088d0111::Translator` for an ANONYMOUS namespace) -- a real, structurally correct +# enclosing scope as far as ctags' own tree is concerned. But an out-of-class DEFINITION written +# INSIDE that same outer namespace's braces never needs to repeat it +# (`namespace tensorflow { ... MlirOptimizationPassRegistry::Global() {...} }` writes +# `MlirOptimizationPassRegistry::Global`, never `tensorflow::MlirOptimizationPassRegistry::Global`; +# an anonymous namespace can't be written at all), so GitGalaxy/tree-sitter's own qualified name +# never includes it either. Confirmed via mlir/mlir_graph_optimization_pass.cc's `tensorflow` +# namespace and mlir/flatbuffer_export.cc's anonymous-namespace-wrapped `Translator` class -- both +# failed the single full-chain containment check this replaced. Tries the FULL chain first, then +# progressively drops the outermost segment, so a genuinely multi-level qualifier that IS written +# out in full (`Object::Connection::operator<`, NVDA/storage.cpp) still matches at its own, +# longer candidate before any shorter one is tried. +def _cpp_qualified_name_candidates(scope_value: str, name: str): + segments = scope_value.split("::") + for i in range(len(segments)): + yield "::".join(segments[i:]) + "::" + name + +# universal-ctags' own C++ parser always renders an operator-overload tag name as `operator X` +# (a literal space between the keyword and the symbol), regardless of whether the source itself +# has a space there -- a fixed ctags naming convention, not a reading of the source text. GitGalaxy +# and tree-sitter both read the identifier as written in source, which for every sampled operator +# overload in this corpus has no space (`operator<`, `operator==`, `operator Variant`'s own +# genuine space before a type name is the one legitimate exception, left untouched). Confirmed via +# the same cpp/function/existence shapes above: stripping this one space resolves the remaining +# `operator <`/`operator ==`/`operator !=`/`operator =` mismatches once scope-qualification (above) +# is also applied. +_CTAGS_OPERATOR_SPACE_RE = re.compile(r"^operator (?=[^A-Za-z_])") + + +def _normalize_cpp_operator_name(name: str) -> str: + return _CTAGS_OPERATOR_SPACE_RE.sub("operator", name) + + def _parse_extension_fields(raw: str) -> dict[str, str]: """Parses `key:value` extension fields from a ctags tag line's tail, tab-separated. The `signature:(...)` field itself can legitimately contain further colons (e.g. Rust's @@ -404,6 +530,16 @@ def read_ctags_symbols(filepath: Path, lang: str) -> list[CtagsSymbol]: "-", "--fields=+n", "--fields=+S", + # ctags truncates its own "verbatim matched source line" pattern field by default + # (confirmed ~100 chars) -- harmless for most tags, but this reader leans on that + # exact text to decide cpp name-qualification (_QUALIFY_NAME_WITH_SCOPE) and + # scoped-vs-unscoped enum detection (_is_cpp_unscoped_enum), both of which need the + # FULL line, not a prefix. Confirmed real, not theoretical: a truncated pattern + # silently broke qualification for godot/editor_node.cpp's + # `Vector> EditorNode:: + # find_resource_conversion_plugin_for_resource(...)` -- the truncated pattern cut off + # mid-identifier before the closing name even appeared. + "--pattern-length-limit=0", f"--language-force={LANG_MAP[lang]}", str(filepath), ], @@ -442,8 +578,20 @@ def read_ctags_symbols(filepath: Path, lang: str) -> list[CtagsSymbol]: kind = trailer_cols[0] if kind not in wanted_kinds: continue + if lang == "cpp" and _is_cpp_unscoped_enum(kind, line[:marker_idx]): + continue fields = _parse_extension_fields("\t".join(trailer_cols[1:])) line_no = int(fields["line"]) if "line" in fields else -1 signature = fields.get("signature") + if lang in _QUALIFY_NAME_WITH_SCOPE: + name = _normalize_cpp_operator_name(name) + source_text = line[:marker_idx] + for scope_key in _CTAGS_SCOPE_KIND_KEYS: + if scope_key in fields: + for candidate in _cpp_qualified_name_candidates(fields[scope_key], name): + if candidate in source_text: + name = candidate + break + break symbols.append(CtagsSymbol(name=name, line=line_no, kind=kind, signature=signature)) return symbols diff --git a/tests/tools/tree_sitter_accuracy_audit.py b/tests/tools/tree_sitter_accuracy_audit.py index e1563a71..155cf329 100755 --- a/tests/tools/tree_sitter_accuracy_audit.py +++ b/tests/tools/tree_sitter_accuracy_audit.py @@ -1638,6 +1638,23 @@ def _get_param_count_declaration_only(node: Any, lang: str) -> int: } ) +def _is_cpp_unscoped_enum(node: Any) -> bool: + """tree-sitter-cpp's `enum_specifier` node covers BOTH a C++11 scoped enum (`enum class Foo + {...}`/`enum struct Foo {...}`) and a plain, unscoped C-style enum (`enum Foo {...}`) -- + distinguished only by whether a `class`/`struct` keyword TOKEN is one of its direct children. + GitGalaxy's own cpp `class_start` regex only counts the SCOPED form as a class-analog; a plain + enum is just a set of named integer constants, not a type with its own scope. Confirmed via + `cpp/class/existence/agree[tree_sitter]_vs[ctags,gitgalaxy]` (22 occurrences, 2026-08-21) -- + same mechanism, same fix, as `tri_comparison_gatherer.py`'s own copy of this helper (this + module owns its own separate walk, see that module's docstring for why). Deliberately NOT + applied to C: C has no scoped-enum syntax at all, so GitGalaxy's own C `class_start` counts + every enum unconditionally already -- gating C the same way would newly create false + negatives, not fix anything.""" + if node.type != "enum_specifier": + return False + return not any(c.type in ("class", "struct") for c in node.children) + + _C_KNOWN_MACRO_HALLUCINATIONS = frozenset( { "if", @@ -2017,7 +2034,16 @@ def walk(node, is_continuation_clause=False): raw_class_name = _get_node_name(node) if raw_class_name: raw_ts_classes.add(raw_class_name) - if lang == "c" and node.child_by_field_name("body") is None: + # cpp shares tree-sitter-c's class-shaped node types (struct_specifier/ + # union_specifier/enum_specifier, plus its own class_specifier), so a bare + # forward declaration (`class Foo;`) is just as bodyless and just as much + # a non-definition here as it is for C -- confirmed via + # cpp/class/existence/agree[gitgalaxy,tree_sitter]_vs[ctags] (95 + # occurrences, e.g. godot/editor_node.h:68's `class + # AudioStreamPreviewGenerator;`). + if (lang in ("c", "cpp") and node.child_by_field_name("body") is None) or ( + lang == "cpp" and _is_cpp_unscoped_enum(node) + ): pass else: name = _get_node_name(node) diff --git a/tests/tools/tri_comparison_gatherer.py b/tests/tools/tri_comparison_gatherer.py index 47bfe6e3..f3fb10f2 100644 --- a/tests/tools/tri_comparison_gatherer.py +++ b/tests/tools/tri_comparison_gatherer.py @@ -111,6 +111,28 @@ class FileReadings: ctags_classes: list[Occurrence] +def _is_cpp_unscoped_enum(node) -> bool: + """tree-sitter-cpp's `enum_specifier` node covers BOTH a C++11 scoped enum (`enum class Foo + {...}`/`enum struct Foo {...}`) and a plain, unscoped C-style enum (`enum Foo {...}`) -- + distinguished only by whether a `class`/`struct` keyword TOKEN is one of its direct children + (confirmed via direct parse: `enum class Foo {...}` has a `class` child between `enum` and the + name, `enum Bar {...}` doesn't). GitGalaxy's own cpp `class_start` regex only counts the + SCOPED form (`enum[ \\t\\n]+class|enum[ \\t\\n]+struct` -- + gitgalaxy/standards/language_standards.py) as a class-analog; a plain enum is just a set of + named integer constants, not a type with its own scope. Confirmed via + `cpp/class/existence/agree[tree_sitter]_vs[ctags,gitgalaxy]` (22 occurrences, 2026-08-21): + every sampled case (`godot/editor_node.h`'s `SceneNameCasing`/`ActionOnPlay`/`ActionOnStop`/ + `MenuOptions`/`MenuType`, `godot/main.h`'s `CLIOptionAvailability`) is a plain `enum Foo {...}` + that GitGalaxy and ctags both correctly agree isn't a class -- only this walker's + unconditional `enum_specifier` counting disagreed. C is deliberately NOT included here: C has + no scoped-enum syntax at all, so GitGalaxy's own C `class_start` counts every enum + unconditionally already (see ctags_reader.py's matching `CTAGS_CLASS_KINDS["c"]` comment) -- + gating C the same way would newly create false negatives, not fix anything.""" + if node.type != "enum_specifier": + return False + return not any(c.type in ("class", "struct") for c in node.children) + + def _walk_tree_sitter(root, func_node_types: set[str], class_node_types: set[str], lang: str): """This module's OWN tree-sitter walk -- deliberately simpler than tree_sitter_accuracy_audit.py's measure()/walk(): list every func/class node's (name, line, @@ -146,6 +168,19 @@ def _walk_tree_sitter(root, func_node_types: set[str], class_node_types: set[str `tree_sitter_accuracy_audit.py`'s walk() already applies for C specifically (not a general-purpose rule -- most languages' class-shaped node types don't have this reference/ definition ambiguity). + + Extended to cpp for the identical reason (found via + `cpp/class/existence/agree[gitgalaxy,tree_sitter]_vs[ctags]`, 95 occurrences): tree-sitter-cpp + inherits the same `class_specifier`/`struct_specifier`/`union_specifier`/`enum_specifier` + grammar from tree-sitter-c, so a bare forward declaration (`class AudioStreamPreviewGenerator;`, + godot/editor_node.h:68) produces the identical bodyless node tree-sitter-c's own reference/cast + case does -- confirmed directly (`node.child_by_field_name("body") is None` for the forward + declaration, not-None for a real `class Foo { ... }` definition). ctags correctly excludes + these; GitGalaxy's own `class_start` regex does NOT (a separate, real GitGalaxy production + defect -- see the GitHub issue filed alongside this fix -- deliberately NOT patched here since + C++ multiple inheritance (`class Foo : public A, public B {`) makes the production engine's + generic comma/paren/equals lookahead unsafe to reuse as-is for cpp without further design work; + this walker instead uses the grammar's own `body` field, which has no such ambiguity). """ funcs: list[Occurrence] = [] classes: list[Occurrence] = [] @@ -161,7 +196,9 @@ def walk(node, is_continuation_clause=False): args=tsaa._get_param_count(node, lang), ) ) - if node.type in class_node_types and not (lang == "c" and node.child_by_field_name("body") is None): + if node.type in class_node_types and not ( + lang in ("c", "cpp") and node.child_by_field_name("body") is None + ) and not (lang == "cpp" and _is_cpp_unscoped_enum(node)): name = tsaa._get_node_name(node) if name: classes.append(Occurrence(name=name, line=node.start_point[0] + 1, args=None))