Skip to content

fix: share inert-region handling and preserve Elixir unquote calls (#357) - #380

Open
LaimaWu wants to merge 22 commits into
redhat-et:mainfrom
LaimaWu:fix/issue-357-inert-regions
Open

LaimaWu wants to merge 22 commits into
redhat-et:mainfrom
LaimaWu:fix/issue-357-inert-regions

Conversation

@LaimaWu

@LaimaWu LaimaWu commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Closes #357.

Problem

Quoted Elixir AST should not produce call edges. Evaluated unquote / unquote_splicing arguments should. Main suppresses both and silently drops quoted call candidates from declined accounting.

Red-first reproduction

The expanded existing elixircheck.sh fails on upstream 255dc199 with unquote(bar(x)) lost its live call edge. A preserved fixture moves from 3 edges / 0 declined to 7 edges / 4 declined; removing its four inert sites moves the declined count by four. Negative controls and red cases cover nested quotes, quote options, declaration/metadata holes, quoted module scope, operator/capture counting and a C++ CDATA marker collision.

Root cause

elixirQuoted treated every quote ancestor as inert. It did not distinguish the quote body from evaluated options or live holes. Declaration/pattern filters and module lookup also followed quoted ancestors into evaluated arguments.

Implementation

A small shared ancestor walker classifies inert boundaries and live holes through an Elixir adapter. Capture extraction and lexical context use the same decision. Current query predicates are not evaluated, and Elixir special forms use ordinary call nodes; inert/live query captures would still need the same target/body classification in C++. The shared hook fits that architecture. No #374 hook-table refactor.

Live-hole semantics

An enabled hole consumes one enclosing quote boundary; walking continues through outer boundaries. A quote nested inside a live hole becomes inert again. Quote option expressions remain live. bind_quoted disables holes by default; literal unquote: true enables them, while false/unknown values remain conservative. Live arguments retain their real lexical module and bypass outer quoted heads/metadata. Ordinary functions named quote / comment, and calls after the region, stay live.

Counted, not dropped

Captured inert ordinary calls, operators and named captures persist as RefRole::Inert. Graph building records existing Declined / caller declinedOut accounting without edges or target candidates. declined= and declined_calls= expose those sites with conditional full/compact explanations. Bare variable-shaped AST does not inflate the count; inert sites create no uses, possible-caller or impact candidates.

Validation and byte identity

Validated final SHA b479b4f against pristine main 255dc19 on macOS, with clean development, G1 and Release/LTO builds.

  • Targeted Elixir gates: 3/3 pass in each build. Existing goldens, cold-repeat determinism, cold/warm parity, XML validity and a full-repository G1 scan pass.
  • Complete regression run: 679 gates: 673 pass, 4 skip, 2 fail; rc=1; tree_writes=0. These raw counts are preserved. oswin32logiccheck fails in libc++23's intentional integer conversion, also reproduced on pristine main; its separate platform-compiler rerun, including sanitizer and mutant controls, passes. The separately scoped editchecknotecheck reference-binary rerun passes. Other skips are the optional argvdiffcheck reference, the unavailable map-section arm and the Apple Silicon portable-build arm on this Intel host.
  • Format/tidy, G1 freshness, extraction-key/scheme tripwires and quality gates pass. Range quality reports 9 minor / 0 gating findings; no quality-ledger changes.
  • 264 raw base/head stdout and stderr pairs are byte-identical, including 249 successful nonempty outputs and 15 equal refusals, with identical absolute inputs/cwd and no normalization. Repository --clones controls include ripwire (total=641) and the vendored tree-sitter runtime snapshot (total=26); C/C++ grammar snapshots have zero clones and serve as additional controls. Existing golden bytes are unchanged.
  • Cache control confirms parser-143 caches are rejected/rebuilt at 145; subsequent warm bytes are stable and warm output matches --no-cache.

Local baseline failure: On this macOS host, memguardcheck B8/B8b fail on both pristine upstream main (255dc19) and this branch: both correctly terminate with rc=5 and no answer, but the real 64M hard-limit reading fires at graph build rather than at the ingest phase asserted by the gate. The four controlled calls use the same compiler, build type, machine, fixture and commands: rc=5, stdout=0 bytes, phase=graph build, and complete stderr is byte-identical. No memory-guard code was changed in this PR. All #357-specific gates and all other non-baseline required gates pass. B8/B8b are not described as passing.

The complete suite uses the documented CI-default environment (optional historical reference-binary variables unset); raw comparison and scoped reference checks are recorded separately.

Clojure / #349 boundary

#349 has not landed. Clojure quote/discard/comment integration remains a follow-up after it lands, as accepted in #357. This PR implements only #357's Elixir arm. Associated optimization-file registration and shifted navigation captures/generated reference are updated separately.

Parser pin

Main uses 143 lean / 144 rich. This branch uses the next free temporary parser value 145 and its quality mirror: train renumbers. Cache 28 / quality scheme 17 remain unchanged; the extraction hash is re-pinned separately.

Summary by CodeRabbit

  • New Features
    • Elixir quote handling now distinguishes executable unquote expressions from inert quoted code, preserving call relationships only for evaluated expressions.
    • Reports now count inert quoted call candidates as declined and explain this count in relevant output.
  • Documentation
    • Clarified how quoted expressions, live holes, and binding options affect call relationships.
    • Updated a command example to reflect the current source line.
  • Bug Fixes
    • Added regression coverage for quote handling, scope, reporting, and consistent results across cache use.

LaimaWu added 22 commits October 5, 2026 06:32
@coderabbitai

coderabbitai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: redhat-et/ripwire/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 9bda39ad-ee50-4d20-8d9d-522277dccf38
📥 Commits

Reviewing files that changed from the base of the PR and between 255dc19 and b479b4f.

⛔ Files ignored due to path filters (2)
  • docs/captures/COMMANDS_showcase_2026-09-14.md is excluded by !docs/captures/**
  • test/qschemetrip.hash is excluded by !test/*.hash
📒 Files selected for processing (21)
  • docs/ARCHITECTURE.md
  • docs/COMMANDS.md
  • queries/elixir/tags.scm
  • scripts/optremarks.py
  • src/compactlegend.h
  • src/graph.h
  • src/graphlegend.h
  • src/ingest.cpp
  • src/ingest_cache.h
  • src/ingest_elixir.h
  • src/ingest_inert.h
  • src/ingest_model.h
  • src/ingest_sidecap.h
  • src/main.cpp
  • src/model.h
  • src/pincensus.h
  • src/quality.h
  • src/serialize.h
  • src/verbs_navigate.h
  • test/elixircheck.sh
  • test/qschemetripcheck.sh

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

Elixir ingestion now distinguishes inert quote syntax from enabled unquote and unquote_splicing holes. Inert call candidates are counted as declined without creating call edges. Map and call-hierarchy output explain the count when it is nonzero.

Changes

Elixir quote semantics and capture

Layer / File(s) Summary
Quote semantics and reference capture
src/model.h, src/ingest_inert.h, src/ingest_elixir.h, src/ingest_sidecap.h, src/ingest.cpp, src/ingest_cache.h, src/quality.h, test/elixircheck.sh, docs/ARCHITECTURE.md, queries/elixir/tags.scm, scripts/optremarks.py, test/qschemetripcheck.sh, docs/COMMANDS.md
Elixir ingestion recognizes enabled holes and retains inert call, operator, and named-capture candidates as Inert references. The parser version changes to 145. Documentation and regression checks cover quote options, lexical scope, cache behavior, and the updated command example.
Inert references in graph accounting
src/ingest_model.h, src/pincensus.h, src/graph.h, test/elixircheck.sh
Inert references receive module-scope ownership and enter graph construction as declined candidates. They increase declinedOut and inertDeclinedCalls without target lookup. Tests check declined counts and the absence of call edges.
Declined-call legends and output
src/graphlegend.h, src/compactlegend.h, src/serialize.h, src/main.cpp, src/verbs_navigate.h, test/elixircheck.sh
Map and call-hierarchy output receives the inert declined-call count. Legends describe inert quote candidates when the count is nonzero. Tests cover compact-legend selection and repeated cached output.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix

Suggested reviewers: joyful-ii-v-i, mfreeman451

Merge Risk: ⚪ Minimal · up to b479b

No merge-blocking issue is established for this change; it is ready for normal merge checks.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: shared inert-region handling and preservation of Elixir unquote calls.
Linked Issues check ✅ Passed #357 requires a shared inert-region mechanism, no call edges from inert references, declined accounting, and a red-first Elixir gate. src/ingest_inert.h supplies the shared ancestor walk, and Elixir…
Out of Scope Changes check ✅ Passed The changed files support #357's implementation, regression coverage, reporting, documentation, optimization-file registration, or parser-version update. The documentation and command-example adjustme…
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

Comment @coderabbitai help to get the list of available commands.

@joyful-ii-V-I

joyful-ii-V-I commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

@LaimaWu this looks great, we are in a couple day delay/holding pattern from using a lot of tokens this weekend (~8 branches of nice improvements almost delivered), get more tokens Wednesday morning...

@joyful-ii-V-I

Copy link
Copy Markdown
Collaborator

Thanks @LaimaWu — this is a lovely first PR: red-first on 255dc199, the unquote / unquote_splicing live holes modelled instead of suppressed, and the declined accounting kept honest. We're back at full capacity and have started our review; we'll aim to fold it into our next integration train.

One housekeeping note: CI hasn't run on this branch yet because GitHub holds workflow runs from a new contributor's fork until a maintainer approves them. That's on our side, not yours, and we'll get it approved.

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.

One shared inert-region mechanism (quote, discard, comment forms) instead of per-language checks

2 participants