Skip to content

fix(zig): wire zig into class_start named-entity extraction - #1367

Merged
squid-protocol merged 3 commits into
mainfrom
fix/zig-class-start-named-extraction-1295
Aug 12, 2026
Merged

squid-protocol merged 3 commits into
mainfrom
fix/zig-class-start-named-extraction-1295

Conversation

@squid-protocol

Copy link
Copy Markdown
Owner

Summary

Extends #1264's per-language class_start named-entity extraction to Zig, per epic #1295's checklist. Zig is the biggest/messiest language in this exercise so far (32 corpus files, real_classes in the hundreds), and the first to land with extra_classes/missing_classes still non-zero by design after investigation -- following the same discipline csharp's enum precedent in #1264 established (document real scope mismatches, don't chase every last case into one PR).

  1. tests/tools/tree_sitter_accuracy_audit.py: ground-truth gap -- zig's error sets (const Foo = error{...};) get their own ErrorSetDecl node type, distinct from ContainerDecl, which NODE_MAPS["zig"] didn't include. GitGalaxy's own class_start regex intentionally matches error sets (its own comment says "Defines structural entities: struct, enum, union, error, opaque"). Added ErrorSetDecl, dispatched through the same _get_zig_container_name resolver ContainerDecl already uses. This alone dropped extra_classes from 10 to 1.
  2. gitgalaxy/standards/language_standards.py: class_start widened with an optional \(/\* step-over between = and the packed/extern modifier, confirmed against two real corpus idioms: a parenthesized-wrapped anonymous struct (const lenAsc = (struct { ... }).lenAsc;) and a pointer-to-opaque handle type (const HMONITOR = *opaque {};, the standard idiom for an opaque OS handle).

The remaining extra_classes=1

Borrowed in bun/MimallocArena.zig is a confirmed tree-sitter-zig grammar limitation, not a GitGalaxy bug: the file uses Zig's newer #field private-field syntax, which the grammar can't parse (has_error=True on that node), so error recovery swallows the container declaration. Same shape as csharp's LanguageParser precedent in #1264.

--regenerate correctly refuses when it sees a raw extra_classes regression (0→1), even though found_classes improved from 0 to 630 in the same run. Per the doc's own documented escape hatch for this exact situation, I hand-blessed tests/tree_sitter_accuracy_baseline_zig.json to the measured numbers and explained why here, same as csharp's precedent.

missing_classes stays non-zero by design

found_classes 0→630 out of real_classes 642→656 (grew because the ErrorSetDecl fix exposed more real declarations). The missing_classes set (23→26 net) breaks down into four understood-but-not-chased shapes, written up as a new recurring-cause class in the checklist doc:

  • Anonymous struct/enum nested inside a generic call argument (const Extra = List(struct { u32 });) -- not the direct declared value.
  • Anonymous struct nested inside an array-element type (const targets = [_]struct {...}{...};).
  • Anonymous type in type-annotation position, not initializer position (var op: enum {...} = .example;) -- recurred 6x in the corpus, the most promising follow-up candidate.
  • A binary chain of named error sets terminating in a literal (const X = A || B || error{C};) -- would need meaningfully more regex complexity to skip safely.

None of these are GitGalaxy bugs or ground-truth bugs -- they're legitimate scope boundaries worth a dedicated follow-up decision rather than folding into this PR.

Result

found_classes 0→630, real_classes 642→656, extra_classes 0→1 (documented, not a bug). zig added to detector.py's _CLASS_START_NAMED_EXTRACTION_LANGS.

Golden master updated (both modes): bun/comptime_string_map.zig's class count 6→7 (the parenthesized-struct fix) and zls/mach/win32.zig's 158→159 (the pointer-to-opaque fix) -- both intentional, all other diffs are downstream numeric fallout of those two signal changes.

Test plan

  • python tests/tools/class_start_diff.py --lang zig -- iterated until only the one confirmed tree-sitter parse-error case remained "extra"
  • python tests/tools/tree_sitter_accuracy_audit.py --lang zig --ci / hand-blessed baseline after --regenerate correctly refused on the documented non-bug regression
  • python tests/tools/tree_sitter_accuracy_audit.py --summary-table
  • python tests/tools/update_golden_master.py --yes in both .crucible_venvs/{full_precision,zero_dependency} (confirmed each venv's editable install resolves to this checkout first)
  • python tests/tools/crucible_check.py (both modes) -- clean, zero diff after regenerating
  • python -m pytest tests/core_engine/ tests/extraction/ -- 6584 passed, 2 skipped, 11 xfailed, 3 xpassed
  • python tests/tools/audit_check.py --regenerate -- ruff baseline regenerated (pure line-shifts from the new comment block only), mypy/dead-key/ast-accuracy all clean

🤖 Generated with Claude Code

squid-protocol and others added 3 commits August 12, 2026 13:37
Two fixes, plus a documented set of ground-truth-vs-regex scope gaps
(same discipline as csharp/go's precedent in #1264):

1. Ground-truth gap: zig's error sets (`const Foo = error{...};`) get
   their own `ErrorSetDecl` node type, distinct from `ContainerDecl` --
   a real class-like entity GitGalaxy's own class_start regex intentionally
   matches (its own comment: "struct, enum, union, error, opaque"), but
   NODE_MAPS["zig"] didn't include it. Added, dispatched through the same
   _get_zig_container_name resolver ContainerDecl already uses. This alone
   dropped extra_classes from 10 -> 1.
2. class_start regex gap: an optional `\(` and `\*` step-over added between
   `=` and the packed/extern modifier, confirmed against two real corpus
   idioms -- a parenthesized-wrapped anonymous struct
   (`const lenAsc = (struct { ... }).lenAsc;`) and a pointer-to-opaque
   handle type (`const HMONITOR = *opaque {};`, the standard idiom for an
   opaque OS handle).

The remaining extra_classes=1 ("Borrowed" in bun/MimallocArena.zig) is a
confirmed tree-sitter-zig grammar limitation: the file uses Zig's newer
`#field` private-field syntax, which the grammar can't parse (has_error=True
on that node), so error recovery swallows the container declaration --
the same shape as csharp's LanguageParser precedent in #1264. Hand-blessed
tests/tree_sitter_accuracy_baseline_zig.json to the measured numbers
(found_classes 0->630, real_classes 642->656, extra_classes 0->1) since
--regenerate correctly refuses on a raw extra_classes regression and this
one isn't a GitGalaxy bug.

missing_classes (23->26, net of the 2 regex fixes minus 5 newly-exposed-by
-the-ErrorSetDecl-fix compound error-union-chain cases) stays non-zero by
design -- documented per-category in
tests/extraction/how_to_extend_class_start_named_extraction.md rather than
chased in this PR: compound error-set unions (`A || B || error{C}`),
if/else conditional anonymous types, type-annotation-position anonymous
types (`var x: enum {...} = ...`), and anonymous structs nested inside a
generic call argument or array-element type (tree-sitter's ancestor walk
finding them regardless of whether they're the direct declared value).

zig added to detector.py's _CLASS_START_NAMED_EXTRACTION_LANGS allowlist.

Golden master updated (both modes): comptime_string_map.zig's class count
6->7 (the parenthesized-struct fix) and win32.zig's 158->159 (the
pointer-to-opaque fix) -- both intentional, all other diffs are downstream
numeric fallout of those two signal changes.

Verified: crucible_check.py (both modes) clean after regenerating the
golden master, core_engine/extraction suite (6584 tests) passes,
audit_check.py clean (ruff baseline regenerated, pure line-shifts only).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Move zig from "ground truth already works" to "done", record the
ErrorSetDecl ground-truth fix, the paren/pointer-sigil regex widening,
and the confirmed tree-sitter parse-error edge case. New recurring-cause
class 7 documents the four scope-mismatch shapes found but not chased
(nested-in-generic-call, nested-in-array-element-type, type-annotation
position, and binary error-set-union chains) so a future pass has the
categorization ready instead of re-deriving it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🐦‍⬛ Muninn Security Scan

✅ No security issues found.

🐦‍⬛ Powered by Muninn · Skald Lab

@squid-protocol
squid-protocol merged commit 84175ff into main Aug 12, 2026
30 of 31 checks passed
@squid-protocol
squid-protocol deleted the fix/zig-class-start-named-extraction-1295 branch August 12, 2026 17:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant