fix(extract): mask bare & in TSX JSX text so partial extraction stops (#2922) - #2934
fix(extract): mask bare & in TSX JSX text so partial extraction stops (#2922)#2934santhiprakash wants to merge 7 commits into
Conversation
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 2 advisory finding(s) below merit a look before merge.
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Adds a _mask_tsx_ampersands pre-parse pass in graphify/extract.py that escapes bare & to & in JSX text content of TSX sources, using a context-stack walker with <-vs-generic disambiguation to leave & in code, strings, comments, and expression containers untouched. Wires the mask into the TSX extraction path so bare-ampersand JSX text no longer produces ERROR nodes and partial-extraction warnings. Adds fixture and unit tests covering ampersand masking and the silent-JSX-text behavior.
Worth a look
- Template literal treated as plain string ignores ${} interpolation and nested JSX —
graphify/extract.py· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- TSX ampersand mask stays in JSX text after closed tags —
graphify/extract.py· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1569 functions depend on the 238 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 477 callers, 42 callees - new:
_rebuild_code()— 98 callers, 50 callees - new:
extract_xaml()— 19 callers, 17 callees - new:
extract_js()— 80 callers, 4 callees - new:
dispatch_command()— 2 callers, 119 callees - new:
_get_extractor()— 26 callers, 6 callees - new:
run_pipeline()— 8 callers, 13 callees - new:
collect_files()— 17 callers, 6 callees - …and 23 more — each is listed as a finding
Verification — 1569 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 1421 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify extract\_js.
The verifier did not have enough to check extract\_js, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
· 1 grounded finding(s) anchored inline below; 30 more finding(s) on lines outside this diff (see the check run).
| return ''.join(out) | ||
|
|
||
|
|
||
| def extract_js(path: Path) -> dict: |
There was a problem hiding this comment.
extract_js()
80 callers depend on it (afferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
d1d687b to
22ae0e9
Compare
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 3 advisory finding(s) below merit a look before merge.
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Adds _mask_tsx_ampersands and its _TSX_ENTITY_RE/_TSX_LT_EXPR_PREV helpers to escape bare & in TSX JSX text to & so tree-sitter parses cleanly instead of emitting ERROR nodes and dropping symbols (#2922), tracking string/comment/tag/expr/jsx_text contexts and disambiguating < as JSX tag vs. generic/comparison. Wires the masking into the TSX extraction path and adds a fixture plus tests covering entity preservation and &-masking elsewhere. Renames/renumbers several extractor engine internal helpers and rationale symbols.
Worth a look
- Closing JSX tags never exit jsx_text state —
graphify/extract.py:980· Escalate · high- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- TSX ampersand mask treats code after a JSX element as JSX text —
graphify/extract.py:986· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- Nested JSX in expression containers is not masked —
graphify/extract.py:995· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1836 functions depend on the 452 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 477 callers, 42 callees - new:
_rebuild_code()— 98 callers, 50 callees - new:
_extract_generic()— 18 callers, 24 callees - new:
extract_xaml()— 19 callers, 17 callees - new:
extract_objc()— 27 callers, 9 callees - new:
extract_js()— 80 callers, 3 callees - new:
dispatch_command()— 2 callers, 119 callees - new:
_get_extractor()— 26 callers, 6 callees - …and 34 more — each is listed as a finding
Verification — 1836 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 1688 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify \_extract\_generic.
The verifier did not have enough to check \_extract\_generic, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
· 42 more finding(s) on lines outside this diff (see the check run).
22ae0e9 to
9a8827a
Compare
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 4 advisory finding(s) below merit a look before merge.
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Adds a _mask_tsx_ampersands pre-parse pass in graphify/extract.py that rewrites bare & in JSX text to & so tree-sitter's TSX grammar parses cleanly instead of emitting ERROR nodes and dropping symbols (#2922). Uses a context-stack walker that distinguishes JSX text from tags, expression containers, strings, comments, and TS code (bitwise &, generic <T> vs JSX tag disambiguation), and short-circuits when the source has no &. Adds tests/test_tsx_jsx_text_ampersand covering entity pass-through and related cases.
Worth a look
- New test module ends with incomplete function definition —
tests/test_tsx_jsx_text_ampersand.py:293· Escalate · high- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- prev_code_keyword substring check via 'return' etc. can false-match identifier suffixes —
graphify/extract.py· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- TSX ampersand mask rewrites regex literals —
graphify/extract.py· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- Fixture test mutates process-wide cwd during extraction —
tests/test_tsx_jsx_text_ampersand.py:69· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1843 functions depend on the 459 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 477 callers, 42 callees - new:
_rebuild_code()— 98 callers, 50 callees - new:
_extract_generic()— 18 callers, 24 callees - new:
extract_xaml()— 19 callers, 17 callees - new:
extract_objc()— 27 callers, 9 callees - new:
extract_js()— 80 callers, 3 callees - new:
dispatch_command()— 2 callers, 119 callees - new:
_get_extractor()— 26 callers, 6 callees - …and 35 more — each is listed as a finding
Verification — 1843 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 1695 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify \_extract\_generic.
The verifier did not have enough to check \_extract\_generic, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
· 1 grounded finding(s) anchored inline below; 42 more finding(s) on lines outside this diff (see the check run).
| ) | ||
|
|
||
|
|
||
| def _mask_tsx_ampersands(src: str) -> str: |
There was a problem hiding this comment.
_mask_tsx_ampersands()
7 callers depend on it (afferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
9a8827a to
4486f5f
Compare
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 2 advisory finding(s) below merit a look before merge.
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Adds a TSX-specific _mask_tsx_ampersands preprocessor (plus _TSX_ENTITY_RE/_TSX_LT_EXPR_PREV) in graphify/extract.py that escapes bare & to & in JSX text content so tree-sitter parses cleanly instead of returning a partial tree (#2922). The masking walks a context stack (tags, strings, comments, expression containers, JSX text) and disambiguates < between JSX tags and generic type parameters to avoid touching bitwise & in code. Includes a new test_tsx_jsx_text_ampersand test.
Worth a look
- TSX ampersand transform violates source_transform byte contract —
graphify/extract.py· Escalate · high- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- Single-letter uppercase JSX tags are misclassified as generics —
graphify/extract.py:965· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1835 functions depend on the 451 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 477 callers, 42 callees - new:
_rebuild_code()— 98 callers, 50 callees - new:
_extract_generic()— 18 callers, 24 callees - new:
extract_xaml()— 19 callers, 17 callees - new:
extract_objc()— 27 callers, 9 callees - new:
extract_js()— 80 callers, 3 callees - new:
dispatch_command()— 2 callers, 119 callees - new:
_get_extractor()— 26 callers, 6 callees - …and 34 more — each is listed as a finding
Verification — 1835 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 1687 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify \_extract\_generic.
The verifier did not have enough to check \_extract\_generic, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
· 42 more finding(s) on lines outside this diff (see the check run).
4486f5f to
8abb48b
Compare
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 2 advisory finding(s) below merit a look before merge.
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Adds _mask_tsx_ampersands (and supporting _TSX_ENTITY_RE / _TSX_LT_EXPR_PREV) to escape bare & to & inside JSX text of TSX source so tree-sitter parses cleanly instead of producing ERROR nodes and dropping symbols (#2922). The masker walks a context stack (tags, expression containers, strings, comments, JSX text) with a < heuristic to distinguish JSX tags from generics/comparisons, leaving bitwise & in code untouched.
Worth a look
- Incomplete statement leaves new test module syntactically invalid —
tests/test_tsx_jsx_text_ampersand.py:294· Escalate · high- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- Multi-character generic arrow type parameters are misclassified as JSX —
graphify/extract.py:969· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1837 functions depend on the 453 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 477 callers, 42 callees - new:
_rebuild_code()— 98 callers, 50 callees - new:
_extract_generic()— 18 callers, 24 callees - new:
extract_xaml()— 19 callers, 17 callees - new:
extract_objc()— 27 callers, 9 callees - new:
extract_js()— 80 callers, 3 callees - new:
dispatch_command()— 2 callers, 119 callees - new:
_get_extractor()— 26 callers, 6 callees - …and 34 more — each is listed as a finding
Verification — 1837 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 1689 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify \_extract\_generic.
The verifier did not have enough to check \_extract\_generic, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
· 42 more finding(s) on lines outside this diff (see the check run).
…Graphify-Labs#2922) tree-sitter-typescript requires & in JSX text (the run between > and < inside a JSX element) to begin an HTML entity reference (&, &#NN;, <, ...). A bare & produces an ERROR node and the partial-extraction path surfaces a parse_errors warning (Graphify-Labs#2551, Graphify-Labs#2788) — even though esbuild, tsc, and React all accept the file. On the reporter's 3000-file TSX codebase, 31 files (~1 %) were silently dropping every function, class, and import — UI labels like "Conexões & Integrações" tripped the gate. The fix is a context-tracking walker that masks bare & to & ONLY in JSX text. & inside JSX tag attribute values, { ... } expression containers, string literals, comments, and TypeScript code (where it is bitwise AND or an intersection type) is left untouched. The walker disambiguates JSX tags from TypeScript generic type-parameter openers (function f<T>, type Bar<T>, <T extends X>, const pick = <T,>(x: T) => x) by combining a previous-non-whitespace character set (operator/punctuation ⇒ JSX, alphanumeric ⇒ code) with a short keyword list (return/yield/new/as/typeof/ void/delete) that flips < after an identifier into JSX context. Already-formed entities (&, &#NN;, <, …) are passed through; multi-ampersand JSX text runs are masked independently. Tag lifecycle is tracked on the context stack: a closing tag pops the element's jsx_text context (returning to code, an expression container, or the parent element's text) and a self-closing tag never opens one, so code following an element — bitwise & included — is never masked (the first cut left jsx_text on the stack after </tag>, corrupting a later "a & b" into "a & b" and reintroducing a parse error). The same tag/generic shape disambiguation runs inside JSX expression containers with expression context forced on, so nested JSX ({ok ? <span>a & b</span> : null}) is masked like top-level JSX. Ambiguous shapes — an identifier directly followed by ``>`` — are split by what follows the ``>``: ``(`` opening a parameter list with an arrow tail (``<T>(x: T) => x``, ``<TKey>(x: TKey): TKey => x``, function-type positions) stays code, while ``<A>VoIP & Chamadas</A>`` — single-letter uppercase components (icon/nav shorthand) and paren-initial JSX text alike — mask their JSX text like any other tag. Misclassifying a generic arrow would strand jsx_text and corrupt a later bitwise ``a & b`` into ``a & b`` (a parse error — the very bug class this mask removes), so the arrow-tail scan is bounded and uppercase-initial is required for the generic reading. The bytes wrapper round-trips with surrogateescape so non-UTF-8 files (latin-1 comments, legacy encodings) keep their bytes exactly: the only byte-level change the transform makes is the ``&`` -> ``&`` insertion itself, never a U+FFFD rewrite of unrelated bytes. Adds tests/test_tsx_jsx_text_ampersand.py (38 tests, including regression canaries for bitwise AND, JSX expression &&, existing &, arrow generics, as cast, JSX attribute &, code after a closed element, self-closing and fragment lifecycle, nested JSX in expression containers, single-letter components vs. single-letter generics, the bytes-mask round-trip contract, and the fixture) and tests/fixtures/tsx_jsx_text_ampersand.tsx (the real-world shape with mixed JSX-text, JSX-attribute, expression-container, and TS-code & in a single file). The mask is wired through a new optional LanguageConfig.source_transform bytes hook applied in _extract_generic's read path, so extract_js() stays a pure suffix→config dispatch with a single file read: the TSX-specific masking lives with _TSX_CONFIG, the walker is unchanged, and non-TSX languages (source_transform unset) parse exactly as before. Vue SFCs with lang="tsx" scripts share _TSX_CONFIG and now get the same mask.
8abb48b to
459c5ce
Compare
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 5 advisory finding(s) below merit a look before merge.
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Adds a TSX ampersand masking pass in graphify/extract.py: _mask_tsx_ampersands walks JSX source and rewrites bare & in JSX text to & so tree-sitter's TSX grammar parses cleanly, backed by helpers _generic_arrow_tail, the _TSX_ENTITY_RE/_TSX_LT_EXPR_PREV tables, and <-disambiguation to keep bitwise & in TS code untouched. Wires the mask into the TSX extraction path and adds fixtures/tests under tests_test_tsx_jsx_text_ampersand covering nested JSX in expression containers, code after JSX elements, and component render cases.
Worth a look
- Dangling pytest decorator leaves test module syntactically invalid —
tests/test_tsx_jsx_text_ampersand.py:313· Escalate · high- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- Single-letter JSX tags with extends-prefixed props are treated as generics —
graphify/extract.py· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- TSX ampersand mask rewrites regex literals as JSX text —
graphify/extract.py· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- TSX source transform is not offset-preserving —
graphify/extract.py:884· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- source_transform changes byte offsets, desyncing node positions from original source —
graphify/extractors/engine.py:2812· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1839 functions depend on the 455 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 477 callers, 42 callees - new:
_rebuild_code()— 98 callers, 50 callees - new:
_extract_generic()— 18 callers, 24 callees - new:
extract_xaml()— 19 callers, 17 callees - new:
extract_objc()— 27 callers, 9 callees - new:
extract_js()— 80 callers, 3 callees - new:
dispatch_command()— 2 callers, 119 callees - new:
_get_extractor()— 26 callers, 6 callees - …and 34 more — each is listed as a finding
Verification — 1839 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 1691 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify \_extract\_generic.
The verifier did not have enough to check \_extract\_generic, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
· 42 more finding(s) on lines outside this diff (see the check run).
Replace the bare & -> & rewrite with a single ASCII space placeholder so the source_transform output stays the same length as the original file. This preserves tree-sitter byte offsets and keeps source[start_byte:end_byte] slices aligned with the user's source. Existing entities (&, &#NN;, etc.) are still passed through unchanged; only bare ampersands in JSX text are masked. Tests and docstrings are updated to assert the byte-preserving contract.
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Adds a TSX JSX-text & masking pass to graphify/extract.py (_mask_tsx_ampersands plus _generic_arrow_tail, _TSX_ENTITY_RE, _TSX_LT_EXPR_PREV), replacing bare & in JSX text with & so tree-sitter-typescript parses cleanly instead of emitting ERROR nodes and partial trees. The walker tracks tag/expression/string/comment/jsx_text contexts and disambiguates < between JSX tags and generic type parameters/comparisons so bitwise & in code stays untouched. Includes new tsx_jsx_text_ampersand fixture and tests covering masked text, passed-through existing entities, and unmasked code after JSX elements.
Worth a look
- TSX ampersand mask rewrites regex literal contents —
graphify/extract.py· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1839 functions depend on the 455 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 477 callers, 42 callees - new:
_rebuild_code()— 98 callers, 50 callees - new:
_extract_generic()— 18 callers, 24 callees - new:
extract_xaml()— 19 callers, 17 callees - new:
extract_objc()— 27 callers, 9 callees - new:
extract_js()— 80 callers, 3 callees - new:
dispatch_command()— 2 callers, 119 callees - new:
_get_extractor()— 26 callers, 6 callees - …and 34 more — each is listed as a finding
Verification — 1839 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 1691 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify \_extract\_generic.
The verifier did not have enough to check \_extract\_generic, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
· 42 more finding(s) on lines outside this diff (see the check run).
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 5 advisory finding(s) below merit a look before merge.
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Adds a TSX preprocessing pass that masks bare & in JSX text content before parsing, via new _mask_tsx_ampersands, _generic_arrow_tail, and supporting regex/char-set constants, to stop tree-sitter-typescript from producing ERROR nodes and partial extractions. Wires the mask into the TSX extraction path across the engine's language walkers and adds test_tsx_jsx_text_ampersand fixtures. The walker disambiguates JSX tags from generics, comparisons, regex literals, and bitwise-AND so only genuine JSX text runs are rewritten.
Worth a look
- TSX source transform uses str despite source_transform receiving bytes —
graphify/extract.py:899· Escalate · high- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- b+1 index may read past end for lone '<' at buffer end —
graphify/extract.py· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- JSX attrs beginning with extends are misclassified as generics —
graphify/extract.py:1060· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- TSX extraction now reports locations/snippets against transformed source instead of the original file —
graphify/extractors/engine.py:2813· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- TSX source transform shifts parser offsets —
graphify/extractors/engine.py:2813· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1839 functions depend on the 455 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 477 callers, 42 callees - new:
_rebuild_code()— 98 callers, 50 callees - new:
_extract_generic()— 18 callers, 24 callees - new:
extract_xaml()— 19 callers, 17 callees - new:
extract_objc()— 27 callers, 9 callees - new:
extract_js()— 80 callers, 3 callees - new:
dispatch_command()— 2 callers, 119 callees - new:
_get_extractor()— 26 callers, 6 callees - …and 34 more — each is listed as a finding
Verification — 1839 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 1691 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify \_extract\_generic.
The verifier did not have enough to check \_extract\_generic, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
· 42 more finding(s) on lines outside this diff (see the check run).
…in TSX mask - Parse the masked TSX bytes but keep the original source bytes for downstream source[start_byte:end_byte] slices, so locations/snippets are reported against the user's file rather than the masked copy. The mask is byte-length-preserving, so offsets stay aligned. - Treat `extends` as a JSX attribute when it is followed by `=`, `>`, `/`, or EOF; only classify it as a generic constraint when a real type expression follows. - Use the already-safely-read `nxt` character for the upper-case check instead of re-indexing `src[b + 1]`. Co-Authored-By: Paperclip <noreply@paperclip.ing>
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 3 advisory finding(s) below merit a look before merge.
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Adds _mask_tsx_ampersands (plus helpers _generic_arrow_tail and the _TSX_* classification tables) in graphify/extract.py, a state-machine walker that rewrites bare & in TSX JSX text to a byte-aligned placeholder so tree-sitter-typescript parses cleanly while leaving & in tags, expression containers, strings, comments, and TS code (bitwise AND) untouched. The <-disambiguation distinguishes JSX tags from generics/comparisons/generic-arrow functions to avoid stranding the walker in jsx_text mode. Adds tsx_jsx_text_ampersand / ..._component test fixtures.
Worth a look
- surrogateescape round-trip is not guaranteed byte-length-preserving —
graphify/extract.py· Escalate · high- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- TSX ampersand mask is not byte-length-preserving for multibyte JSX text, misaligning offsets —
graphify/extract.py· Escalate · high- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- TSX source transform uses str contract where extractor passes bytes —
graphify/extract.py:900· Escalate · high- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1839 functions depend on the 455 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 477 callers, 42 callees - new:
_rebuild_code()— 98 callers, 50 callees - new:
_extract_generic()— 18 callers, 24 callees - new:
extract_xaml()— 19 callers, 17 callees - new:
extract_objc()— 27 callers, 9 callees - new:
extract_js()— 80 callers, 3 callees - new:
dispatch_command()— 2 callers, 119 callees - new:
_get_extractor()— 26 callers, 6 callees - …and 34 more — each is listed as a finding
Verification — 1839 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 1691 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify \_extract\_generic.
The verifier did not have enough to check \_extract\_generic, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
· 42 more finding(s) on lines outside this diff (see the check run).
…ssion checks The previous graphify-labs review raised three advisory high findings about surrogateescape, multibyte JSX text, and the str/bytes contract. These tests lock in the byte-preserving behavior that the implementation already provides: the transform is bytes -> bytes, every non-& byte round-trips unchanged (including non-UTF-8 surrogateescape bytes and multibyte UTF-8), and only a bare & in JSX text becomes a single ASCII space. Co-Authored-By: Paperclip <noreply@paperclip.ing>
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Adds TSX-specific preprocessing to extract.py that masks bare & in JSX text content before parsing, via a new _mask_tsx_ampersands walker (with helpers _generic_arrow_tail, _lt, and the _TSX_* regex/char-set constants) that distinguishes JSX tags from generics, comparisons, regex literals, strings, and expression containers. Wires the mask into the TSX extraction path so files with unescaped & parse cleanly instead of producing ERROR nodes and partial-extraction warnings (#2551, #2922). Includes test_tsx_jsx_text_ampersand_extract covering the new behavior.
Worth a look
- TSX mask alters byte length for non-BMP chars, breaking offset alignment —
graphify/extract.py· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1841 functions depend on the 457 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 477 callers, 42 callees - new:
_rebuild_code()— 98 callers, 50 callees - new:
_extract_generic()— 18 callers, 24 callees - new:
extract_xaml()— 19 callers, 17 callees - new:
extract_objc()— 27 callers, 9 callees - new:
extract_js()— 80 callers, 3 callees - new:
dispatch_command()— 2 callers, 119 callees - new:
_get_extractor()— 26 callers, 6 callees - …and 34 more — each is listed as a finding
Verification — 1841 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 1693 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify \_extract\_generic.
The verifier did not have enough to check \_extract\_generic, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
· 42 more finding(s) on lines outside this diff (see the check run).
…d mask The latest graphify-labs review flagged an advisory that the TSX mask alters byte length for non-BMP characters and breaks offset alignment. Add a non-BMP (4-byte UTF-8 🚀) case to the byte-preservation parametrize and an end-to-end extraction test to prove the mask stays byte-length-preserving and that the file extracts silently. Co-Authored-By: Paperclip <noreply@paperclip.ing>
There was a problem hiding this comment.
Graphify reviewed this change.
Worth a look — the grounded gate found no coupling regressions or blocking issues, but 3 advisory finding(s) below merit a look before merge.
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Adds a TSX preprocessing pass in graphify/extract.py that masks bare & in JSX text content so tree-sitter's strict TSX grammar parses cleanly instead of emitting ERROR nodes and dropping symbols (#2922). The core is _mask_tsx_ampersands, a context-stack walker with <-disambiguation helpers (_generic_arrow_tail) to distinguish JSX tags from generics/comparisons and leave bitwise & in code untouched. Wires the mask into the TSX extraction path and adds a regression test asserting code after a JSX element is not masked.
Worth a look
- _generic_arrow_tail return-type branch uses find(';') which can span past arrow —
graphify/extract.py· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- TSX source transform violates byte-oriented source_transform contract —
graphify/extract.py· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
- source_transform contract omits required byte-length preservation —
graphify/extractors/models.py:56· Escalate · medium- agreed by 2 of 2 members but NOT verified (no proof, no reproducing execution) — consensus is not a verdict; needs human review
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1843 functions depend on the 459 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 477 callers, 42 callees - new:
_rebuild_code()— 98 callers, 50 callees - new:
_extract_generic()— 18 callers, 24 callees - new:
extract_xaml()— 19 callers, 17 callees - new:
extract_objc()— 27 callers, 9 callees - new:
extract_js()— 80 callers, 3 callees - new:
dispatch_command()— 2 callers, 119 callees - new:
_get_extractor()— 26 callers, 6 callees - …and 34 more — each is listed as a finding
Verification — 1843 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 1695 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify \_extract\_generic.
The verifier did not have enough to check \_extract\_generic, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
· 42 more finding(s) on lines outside this diff (see the check run).
…SX ampersand mask
- Replace the `src.find(';', j)` return-type bound in `_generic_arrow_tail`
with a depth-aware scan that skips `;` inside object types and other nested
delimiters, and skips `)` inside strings/regex in the parameter list.
- Update the stale ampersand-mask comment to describe the actual one-byte
space placeholder and byte-alignment contract.
- Document the `LanguageConfig.source_transform` byte-length preservation
requirement in `extractors/models.py`.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
There was a problem hiding this comment.
Graphify reviewed this change.
Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Adds a TSX preprocessing pass in graphify/extract.py that masks bare & in JSX text content before parsing, so tree-sitter's strict TSX grammar no longer emits ERROR nodes and drops the file's symbols (#2922). The new _mask_tsx_ampersands walker distinguishes JSX text from tags, expression containers, strings, comments, regex, and generic type parameters (via _generic_arrow_tail and the </regex heuristics), replacing each bare & with a single space to keep byte offsets aligned. Includes tests/test_tsx_jsx_text_ampersand covering entity pass-through.
No blocking issues surfaced. 7 lower-confidence candidates did not survive cross-model review.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 1848 functions depend on the 464 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 477 callers, 42 callees - new:
_rebuild_code()— 98 callers, 50 callees - new:
_extract_generic()— 18 callers, 24 callees - new:
extract_xaml()— 19 callers, 17 callees - new:
extract_objc()— 27 callers, 9 callees - new:
extract_js()— 80 callers, 3 callees - new:
dispatch_command()— 2 callers, 119 callees - new:
_get_extractor()— 26 callers, 6 callees - …and 34 more — each is listed as a finding
Verification — 1848 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 1700 function(s) in the blast radius were not formally verified this run
Formal verification
Could not verify: Could not verify \_extract\_generic.
The verifier did not have enough to check \_extract\_generic, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
· 42 more finding(s) on lines outside this diff (see the check run).
Summary
A bare
&inside TSX JSX text (e.g.<div>VoIP & Chamadas</div>) is valid TSX — esbuild, tsc, and React all accept it — but tree-sitter-typescript's grammar requires&in JSX text to begin an HTML entity reference. The resulting ERROR node trips the partial-extraction path (#2551 / #2788) and, on the reporter's 3000-file TSX codebase, silently drops every function, class, and import from 31 files (1 %), all because UI labels use&as a natural-language connector (Conexões & Integrações,Configurações & Perfil,Privacidade & LGPD).Fix
A small, context-tracking walker that masks bare
&to a single ASCII space only in JSX text content.&is left untouched everywhere the grammar already accepts it:<a href="/search?q=a&b=c">),{ ... }expression containers ({flag && <span/>}),&is bitwise AND (0xff & 0x0f) or an intersection type (type X = A & B).Already-formed entities (
&,&#NN;,<, …) are passed through without double-masking.A single-byte placeholder (ASCII space) is used instead of the entity
&so the transformed source stays the same length as the original file. This keeps tree-sitter byte offsets andsource[start_byte:end_byte]slices aligned with the user's source, honoring theLanguageConfig.source_transformbyte contract. Vue's non-script blanking uses the same offset-preserving approach.The walker disambiguates JSX tag starts from TypeScript generic type-parameter openers by combining a previous-non-whitespace character set (operator/punctuation ⇒ JSX, alphanumeric ⇒ code) with a short keyword list (
return/yield/new/as/typeof/void/delete) that flips<after an identifier into JSX context.<T>,<T,>,<T extends X>,<T = X>, and<T>(...) => ...are all treated as code (generic shape) so subsequent bitwise&in code is not masked.Verification
tests/test_tsx_jsx_text_ampersand.py— 38 tests, all green. Covers the fixture (mixed JSX-text / JSX-attribute / expression-container / TS-code&in a single file), bare&in JSX text is silent, bitwise AND in TS code is preserved,&&in JSX expression is preserved, existing&passes through, mask is fully byte-preserving, every non-JSX-text&location is left intact, fast-path for empty/no-ampersand sources, multi-bare-ampersand JSX text runs.tests/test_extract.py,tests/test_file_slice.py— 212 passed, 4 skipped. No regressions.graphify update .re-extracted the repo and updated the local graph output.Reproduction (before fix)
After the fix,
A()extracts cleanly with no parse_errors.Closes #2922.