**Purpose.** This feature turns on a real structured parse for overlay adjudication by installing an optional extra. AppSec scans of JavaScript, C/C++, Java, and Python then get `FileIR` from official tree-sitter grammars instead of `language_unsupported`.
**Users.** Default/CI installs keep `quick` and extra-free pytest. Operators who install `openultrasast[semantic]` get overlay promote/demote on the in-scope languages.
**Impact.**`parse_file` prefers extra grammars when they load. The dead CLI parse-success path is removed. Taint, facts, dispositions, sandbox, and the detection gate do not change.
### Goals
- Optional extra with official grammar wheels; core `dependencies` stay empty.
- One CST walker into existing `FileIR` (`Bind`, `CallSite`, `FunctionIR`).
- Fail closed: missing extra, missing grammar, or error tree → `unadjudicated`.
- Dual test matrix: extra-free always; extra-on JS plus C or Java.
- Existing `FileIR` types and `parse_file` callers (`taint.py`, `overlay.py`).
-`harness_ext` capability-guard pattern (find_spec, no import at module load).
- External: PyPI `tree-sitter` and grammar packages listed in Technology Stack (extra only).
### Revalidation Triggers
- Changing `FileIR` / `Bind` / `CallSite` fields.
- Importing `tree_sitter` at module load of `cli` or `semantic/__init__`.
- Adding core (non-extra) parser dependencies.
- Using host `tree-sitter` CLI output as overlay IR.
## Architecture
### Existing Architecture Analysis
Overlay already calls `parse_file` → taint → dispositions. Python `ast` works. `parse_tree_sitter_cli` always returns `None`. `tree_sitter_available()` is true if a CLI binary exists, which does not imply a grammar.
### Architecture Pattern and Boundary Map
Selected: **hybrid extra guard + CST walker + existing dispatch.** Same packaging seam as HarnessX. `parse_file` remains the only overlay parse entry.
```mermaid
flowchart TD
overlay[overlay adjudicate]
parse[parse_file]
extra[has_semantic_extra]
gram[grammar_for language]
cst[cst walker]
ast[python ast]
fail[FileIR language_unsupported or parse_failed]
taint[taint on FileIR]
overlay --> parse
parse --> extra
extra -->|yes| gram
gram -->|loaded| cst
cst -->|has_error| fail
cst -->|ok| taint
extra -->|no| ast
gram -->|missing| ast
ast -->|python ok| taint
ast -->|not python| fail
```
**Key decisions**
- Extra grammars are the product parse. Host CLI is not a success path.
- Taint does not import tree-sitter.
- Dependency direction: extra guard → cst walker → `parse_file` → taint → overlay. No reverse imports.
### Technology Stack
| Layer | Choice / Version | Role in Feature | Notes |
- Integration: only `parse_file` calls this after `grammar_for`.
- Validation: JS `eval(req.query.x)` and C `printf("%s\\n", data)` fixtures with extra on.
- Risks: node-type aliases (JS `assignment_pattern`); table is the extension point, not a new visitor module per language.
#### ParseDispatch
| Field | Detail |
|-------|--------|
| Intent | Existing `parse_file` with extra-first order |
| Requirements | 2.1, 3.3–3.5, 4.2, 4.3 |
Order: grammar_for → cst; else python ast if `language == python`; else `language_unsupported`. Do not call host CLI for overlay IR.
## Data Models
`FileIR`, `Bind`, `CallSite`, `FunctionIR` stay as in `ir.py`. No new disposition. `engine` values: `tree-sitter` | `python-ast` | `none`.
## Error Handling
| Condition | Overlay | Scan |
|-----------|---------|------|
| Extra not installed | language_unsupported for non-Python | standard succeeds |
| Grammar missing for language | language_unsupported or Python ast | standard succeeds |
| root.has_error | parse_failed | standard succeeds |
| Wheel import error | treat as extra absent | do not raise |
## Testing Strategy
- Unit extra-free: import `openultrasast.cli` does not import `tree_sitter`; JS `parse_file` → `language_unsupported`; Python ast still promotes `eval(request.args)`; `quick` scan unchanged (1.1–1.3, 3.1, 3.3, 6.1).
- Unit extra-on (`pytest.mark.semantic`): JS `eval(req.query.x)` overlay `promote` (2.2); C `printf("%s\\n", data)` overlay `demote` with dominating fact (2.3); syntax-broken JS → `parse_failed` (3.4); `engine == tree-sitter` on success (2.1).
- Skip: if `not has_semantic_extra()`, marked tests skip, extra-free suite green (6.3).
- CI: default job extra-free; second job installs extra and runs `-m semantic` (6.2).
- Do not assert detection-gate Youden (5.5).
## Security Considerations
Parser wheels run in-process on operator source. Same trust as reading the tree today. Extra does not execute target code. Overlay evidence stays `static_corroboration` or below (5.3).
## Performance
Parse is per-file MAP, same file budget as rank. No whole-program index.
## Migration Strategy
Default install behavior unchanged. Operators who want JS/C/Java overlay run `uv sync --extra semantic`. No artifact format migration.
## Supporting References
Grammar load sketch (not runtime-imported in core):