Skip to content

fix(native): bump tree-sitter to 0.25 + ABI regression test (#1054)#1060

Merged
carlos-alm merged 4 commits into
mainfrom
fix/issue-1054-tree-sitter-abi
May 4, 2026
Merged

fix(native): bump tree-sitter to 0.25 + ABI regression test (#1054)#1060
carlos-alm merged 4 commits into
mainfrom
fix/issue-1054-tree-sitter-abi

Conversation

@carlos-alm
Copy link
Copy Markdown
Contributor

Summary

  • Real fix for the HCL .tf drops in perf(native): ~2 second flat overhead added to rebuild operations in v3.10.0 #1054. tree-sitter-hcl 1.1.0 ships parser code built for tree-sitter ABI 15; `crates/codegraph-core` was pinned at `tree-sitter = "0.24"` (ABI 14). At runtime, `Parser::set_language` rejects the grammar with `LanguageError { version: 15 }`, `parse_file` returns `None`, and every `.tf` file gets dropped — same behavior in both gcc and clang builds.
  • Bumps `tree-sitter` to `"0.25"` (resolves to 0.25.10). The 0.25 runtime supports both ABI 14 and 15 grammars, so older grammar crates continue to load without their own bumps.
  • Adds two regression tests in `parser_registry.rs` so the next ABI drift is caught at PR-time instead of silently on a release run, and wires `cargo test` into the `native-host-build` CI job so the tests actually run.

Why this catches the regression

`all_grammars_have_compatible_abi` iterates `LanguageKind::all()`, calls `Parser::set_language` on every variant, and fails the test if any one returns `LanguageError`. Without the Cargo.toml bump in this PR, this test fails immediately with `Hcl: LanguageError { version: 15 }`.

`all_kinds_listed_in_all` is a no-op exhaustive match. If someone adds a new `LanguageKind` variant but forgets to add it to `all()`, this match fails to compile — preventing silent ABI-coverage gaps for new languages.

Test plan

  • `cargo test --release` in `crates/codegraph-core`: 183 tests pass, including both new ones.
  • Verified the test fails on the unfixed code: with `tree-sitter = "0.24"`, `all_grammars_have_compatible_abi` reports `Hcl: LanguageError { version: 15 }`.
  • CI `native-host-build` matrix passes on Linux/macOS/Windows with the new `cargo test` step.

Companion PRs

What this does not solve

The pre-publish gate also showed a separate ~2-second-per-call CI overhead on the native engine that isn't explained by the .tf drops (my Docker reproduces the drops with no equivalent slowdown). Tracking that separately — instrumentation patch coming.

Refs #1054

The HCL extractor in codegraph-core was silently dropping every .tf file
at runtime because `tree-sitter-hcl` 1.1.0 ships a parser built for
tree-sitter ABI 15 while the host crate was pinned at `tree-sitter = "0.24"`
(ABI 14). `Parser::set_language` rejects the grammar with
`LanguageError { version: 15 }`, `parse_file` returns `None`, and the JS
engine-parity layer reports the file as a "drop" — triggering an expensive
WASM backfill on every build. See #1054.

Three changes:

- `Cargo.toml`: bump `tree-sitter = "0.25"`. Resolves to 0.25.10. ABI 15
  runtime supports both ABI 14 and 15 grammars, so the older grammar
  crates (most are on `0.23`/`0.24`) continue to load without their own
  bumps.

- `Cargo.lock`: regenerated. Brings in `tree-sitter 0.25.10`,
  `indexmap 2.14`, `hashbrown 0.17`, `equivalent 1.0`. The
  `codegraph-core` package row also re-syncs from `3.9.5` to `3.9.6`,
  which had drifted independently.

- `parser_registry.rs`: adds `LanguageKind::all()` plus a `#[cfg(test)]`
  module with two regression tests:
    - `all_grammars_have_compatible_abi` iterates `all()` and asserts
      `Parser::set_language` succeeds for every grammar. This is the test
      that catches the next ABI mismatch the moment it lands in the
      lockfile, instead of after we ship a broken release.
    - `all_kinds_listed_in_all` is an exhaustive match over `LanguageKind`
      that fails to compile if a new variant is added without being
      listed in `all()` — preventing silent ABI-coverage gaps when
      languages are added.

- `ci.yml`: adds `cargo test --release` to the `native-host-build` job so
  these tests actually run in CI. Without this, the regression test would
  only run when someone manually invoked cargo, defeating its purpose.

Verified locally: 183 cargo tests pass, including both new ones.
Without this PR, `all_grammars_have_compatible_abi` fails on `Hcl` with
`LanguageError { version: 15 }`.

Refs #1054
@claude
Copy link
Copy Markdown

claude Bot commented May 4, 2026

Claude finished @carlos-alm's task —— View job


Reviewing PR: tree-sitter ABI bump fix

Review Checklist

  • Read and analyze all changed files
  • Perform root cause analysis
  • Check for configuration changes and test integrity
  • Review code quality and implementation
  • Assess backlog compliance criteria
  • Provide final assessment and recommendation

Root Cause Analysis

Problem Being Solved: HCL .tf files were being silently dropped due to tree-sitter ABI version mismatch. tree-sitter-hcl 1.1.0 ships with ABI 15 parser code, but crates/codegraph-core was pinned at tree-sitter = "0.24" (ABI 14). At runtime, Parser::set_language rejects the grammar with LanguageError { version: 15 }, causing parse_file to return None and every .tf file to be dropped.

Why This Approach: This is the correct root cause fix. Bumping to tree-sitter 0.25.10 provides ABI 15 support while maintaining backward compatibility with ABI 14 grammars. The regression tests ensure this drift is caught at PR-time rather than silently in production.

Risk Assessment: ✅ Low risk - this is a dependency version bump with comprehensive test coverage. Tree-sitter 0.25 maintains backward compatibility, and the new tests prevent future regressions.

Configuration Changes Review

  • CI Changes: ✅ Adding cargo test --release to native-host-build is appropriate - it ensures ABI regression tests actually run during CI
  • Dependency Changes: ✅ tree-sitter 0.24 → 0.25 is the correct fix, maintains backward compatibility
  • No rules relaxed: ✅ No linting, testing, or build rules were weakened

Test Integrity Review

New Regression Tests ✅ EXCELLENT

all_grammars_have_compatible_abi() (parser_registry.rs:196-211):

  • Purpose: Iterates all LanguageKind::all() variants and verifies Parser::set_language() succeeds
  • Effectiveness: Would have caught the HCL ABI 15 vs 14 mismatch immediately
  • Coverage: Tests every supported language grammar, not just the problematic ones
  • Error reporting: Clear failure messages with specific variant and error details

all_kinds_listed_in_all() (parser_registry.rs:217-250):

  • Purpose: Compile-time exhaustiveness check prevents silent coverage gaps
  • Mechanism: Exhaustive match that fails to compile if a LanguageKind variant is added without updating all()
  • Future-proof: Guards against new languages being added but missing ABI coverage

Test Implementation Quality ✅

  • Clean, well-documented test code with clear failure messages
  • Proper integration into existing test infrastructure
  • Tests are focused and single-purpose
  • No weakened assertions or conditional logic

Code Quality Review

Changes Are Minimal and Focused ✅

  • Cargo.toml: Single line change tree-sitter = "0.25" (line 15)
  • CI workflow: 7-line addition to run cargo test --release with clear documentation
  • Regression tests: 69 well-structured lines with comprehensive coverage
  • Cargo.lock: Automated dependency resolution updates

Implementation Quality ✅

Technical Correctness ✅

  • ABI compatibility: tree-sitter 0.25 supports both ABI 14 and 15 grammars
  • Backward compatibility: No breaking changes to existing functionality
  • Test coverage: 100% language coverage via exhaustive enum iteration

Backlog Compliance

  • Zero-dep: ✅ — No new runtime dependencies added, builds on existing tree-sitter infrastructure
  • Foundation-aligned: ✅ — Maintains always-current graph (P1), fixes core parsing without adding complexity
  • Problem-fit: 5 — Directly prevents file drops that would cause "missed blast radius" - core problem codegraph exists to solve
  • Breaking: No — Purely additive fix, no API or behavior changes
  • Tier: 1 — Zero-dep + foundation-aligned = highest priority tier

Critical Concerns

None. This is an exemplary fix:

  • Addresses the real root cause without workarounds
  • Includes comprehensive regression testing
  • Minimal, focused changes with proper documentation
  • Zero risk of introducing new issues

Final Assessment

## Root Cause Analysis
**Problem Being Solved**: Tree-sitter ABI version mismatch causing HCL .tf files to be silently dropped
**Why This Approach**: Correct dependency bump + comprehensive regression tests to prevent future occurrence  
**Risk Assessment**: Low risk, backward-compatible dependency update with full test coverage

## Backlog Compliance  
- Zero-dep: ✓ — builds on existing tree-sitter infrastructure
- Foundation-aligned: ✓ — maintains core parsing accuracy 
- Problem-fit: 5 — directly prevents file drops/missed blast radius
- Breaking: No
- Tier: 1

## Critical Concerns
None

## Final Recommendation
- Rating: ⭐⭐⭐⭐⭐ (5/5)
- Action: **APPROVE**
- Reasoning: Exemplary fix that addresses root cause with comprehensive testing and zero risk

This PR demonstrates excellent engineering practice - it identifies the real problem, implements the minimal correct fix, and adds robust safeguards to prevent regression. The ABI compatibility tests are particularly well-designed and will prevent this class of issue in the future.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 4, 2026

Greptile Summary

Bumps tree-sitter from 0.24 to 0.25 (resolves to 0.25.10) to fix the ABI 14 vs 15 mismatch that caused tree-sitter-hcl 1.1.0 to silently drop all .tf files at runtime. Adds two regression tests — one exhaustive compile-time coverage check and one runtime ABI probe — and wires cargo test --release into the native-host-build CI job so future grammar/runtime version drift fails at PR time.

Confidence Score: 5/5

This PR is safe to merge — it fixes a confirmed runtime regression with a targeted version bump and adds meaningful regression tests.

No P0 or P1 findings. The Cargo.toml bump is minimal and correct, Cargo.lock changes are consistent, the regression tests are well-designed (compile-time exhaustiveness + runtime ABI probe), and the CI integration is straightforward. The redundant clang step is correctly documented as intentionally deferred to a follow-up revert.

No files require special attention.

Important Files Changed

Filename Overview
crates/codegraph-core/Cargo.toml Bumps tree-sitter from 0.24 to 0.25; all grammar crates remain at their current pins since 0.25 supports both ABI 14 and 15.
crates/codegraph-core/src/parser_registry.rs Adds LanguageKind::all() and two regression tests (runtime ABI probe + compile-time exhaustive match) to prevent future silent grammar drops.
.github/workflows/ci.yml Updates the clang-step comment to acknowledge it's now redundant, and adds a cargo test --release step to run ABI regression tests in CI.
Cargo.lock Lock file updated for tree-sitter 0.25.10 and its new transitive dependencies (serde_json with indexmap/equivalent via preserve_order feature, hashbrown 0.17.0).

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[cargo test --release] --> B[all_grammars_have_compatible_abi]
    A --> C[all_kinds_listed_in_all]

    B --> D{Parser::set_language\nfor each LanguageKind::all}
    D -->|ABI match| E[pass]
    D -->|LanguageError| F[collect failure\nfail test]

    C --> G[Exhaustive compile-time match\nover all LanguageKind variants]
    G -->|missing variant| H[compile error]
    G -->|all present| I[assert_eq all len == EXPECTED_LEN]
    I -->|mismatch| J[runtime failure]
    I -->|match| K[pass]

    subgraph ABI Fix
        L[tree-sitter 0.24\nABI 14 only] -->|rejects HCL grammar| M[parse_file returns None\nsilently drops .tf files]
        N[tree-sitter 0.25\nABI 14 + 15] -->|accepts HCL grammar| O[.tf files parsed correctly]
    end
Loading

Reviews (2): Last reviewed commit: "ci: clarify clang step is redundant afte..." | Re-trigger Greptile

Comment on lines 249 to 251
assert_eq!(LanguageKind::all().len(), 24);
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 The assert_eq!(LanguageKind::all().len(), 24) check doesn't fully close the gap it aims to close. If a developer adds a new variant to the enum (forced by the compile-time match) but forgets to add it to all() and also forgets to bump this count, both the compile check and the runtime assertion pass silently — the new language gets zero ABI coverage. The assertion only catches someone who updates all() but forgets to bump the number, which is the less dangerous case. Naming the constant and improving the assertion message would make the three required update sites more explicit.

Suggested change
assert_eq!(LanguageKind::all().len(), 24);
}
}
// IMPORTANT: this constant must equal the number of arms in the match
// above AND the length of the slice returned by `LanguageKind::all()`.
// Because both checks require the same manual update, they reinforce
// each other: a developer who updates the match is reminded to also
// update `all()` and this count.
const EXPECTED_LEN: usize = 24;
assert_eq!(
LanguageKind::all().len(),
EXPECTED_LEN,
"A LanguageKind variant is in the exhaustive match but missing from \
`all()` (or vice-versa). Update `all()` and bump EXPECTED_LEN.",
);
}
}

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 122da28 — applied the suggested EXPECTED_LEN constant rename and the clearer assertion message verbatim. Both regression tests still pass locally.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 4, 2026

Codegraph Impact Analysis

3 functions changed0 callers affected across 0 files

  • LanguageKind.all in crates/codegraph-core/src/parser_registry.rs:173 (0 transitive callers)
  • all_grammars_have_compatible_abi in crates/codegraph-core/src/parser_registry.rs:196 (0 transitive callers)
  • all_kinds_listed_in_all in crates/codegraph-core/src/parser_registry.rs:217 (0 transitive callers)

carlos-alm added 3 commits May 4, 2026 12:59
…1060)

Addresses Greptile feedback: rename the bare `24` literal in the
`all_kinds_listed_in_all` test to a named `EXPECTED_LEN` constant
with a comment that points at all three update sites (the exhaustive
match, `LanguageKind::all()`, and the constant itself), plus a
clearer assertion message that names the failure mode.
Addresses Greptile feedback: the comment on the clang step claimed
clang produced a working binary, but the real root cause of the .tf
drop was a tree-sitter ABI mismatch — gcc and clang both fail at the
same ABI check. With the tree-sitter 0.25 bump in this PR the clang
override is redundant. Update the comment to reflect that, and note
that the step itself is removed by a follow-up revert PR to keep this
PR scoped to the ABI fix.
@carlos-alm
Copy link
Copy Markdown
Contributor Author

@greptileai addressed both review findings:

  • parser_registry.rs:251 (P2): Applied the suggested fix in 122da28 — renamed the bare 24 literal to a named EXPECTED_LEN constant with a comment that points at the three update sites, and rewrote the assertion message to name the failure mode. Both regression tests still pass locally (cargo test --release parser_registry).
  • ci.yml:64-72 (P2, comments-outside-diff): Updated the stale clang-step comment in b7fa204. The previous wording ("Clang produces a working binary") was misleading because the real root cause was the tree-sitter ABI mismatch, not gcc-vs-clang. The new comment notes that the clang override is now redundant after the 0.25 bump and that the step itself is removed by a follow-up revert PR (kept here to keep this PR scoped to the ABI fix).

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 4, 2026

Both fixes look good — the commits match exactly what was described.

  • 122da28: EXPECTED_LEN constant with update-site comments and a descriptive assertion message — addresses the magic-number concern cleanly.
  • b7fa204: CI comment now accurately attributes the .tf drops to the ABI mismatch rather than the gcc/clang distinction, and flags the step for removal in the follow-up revert PR.

Both P2 findings are resolved. The PR is ready from my side.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

@carlos-alm carlos-alm merged commit 3ead0f8 into main May 4, 2026
31 checks passed
@carlos-alm carlos-alm deleted the fix/issue-1054-tree-sitter-abi branch May 4, 2026 21:15
@github-actions github-actions Bot locked and limited conversation to collaborators May 4, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant