diff --git a/Cargo.lock b/Cargo.lock
index 9078d52..1b513b0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -432,7 +432,7 @@ dependencies = [
 
 [[package]]
 name = "codegraph-bench"
-version = "0.33.0"
+version = "0.34.0"
 dependencies = [
  "anyhow",
  "clap",
@@ -447,7 +447,7 @@ dependencies = [
 
 [[package]]
 name = "codegraph-core"
-version = "0.33.0"
+version = "0.34.0"
 dependencies = [
  "anyhow",
  "serde",
@@ -463,7 +463,7 @@ dependencies = [
 
 [[package]]
 name = "codegraph-daemon"
-version = "0.33.0"
+version = "0.34.0"
 dependencies = [
  "anyhow",
  "codegraph-core",
@@ -483,7 +483,7 @@ dependencies = [
 
 [[package]]
 name = "codegraph-extract"
-version = "0.33.0"
+version = "0.34.0"
 dependencies = [
  "anyhow",
  "codegraph-core",
@@ -518,6 +518,7 @@ dependencies = [
  "tree-sitter-ruby",
  "tree-sitter-rust",
  "tree-sitter-scala",
+ "tree-sitter-solidity",
  "tree-sitter-swift",
  "tree-sitter-typescript",
  "tree-sitter-xml",
@@ -526,7 +527,7 @@ dependencies = [
 
 [[package]]
 name = "codegraph-graph"
-version = "0.33.0"
+version = "0.34.0"
 dependencies = [
  "anyhow",
  "codegraph-core",
@@ -540,7 +541,7 @@ dependencies = [
 
 [[package]]
 name = "codegraph-mcp"
-version = "0.33.0"
+version = "0.34.0"
 dependencies = [
  "anyhow",
  "axum",
@@ -563,7 +564,7 @@ dependencies = [
 
 [[package]]
 name = "codegraph-resolve"
-version = "0.33.0"
+version = "0.34.0"
 dependencies = [
  "anyhow",
  "codegraph-core",
@@ -577,7 +578,7 @@ dependencies = [
 
 [[package]]
 name = "codegraph-rs"
-version = "0.33.0"
+version = "0.34.0"
 dependencies = [
  "anyhow",
  "assert_cmd",
@@ -613,7 +614,7 @@ dependencies = [
 
 [[package]]
 name = "codegraph-store"
-version = "0.33.0"
+version = "0.34.0"
 dependencies = [
  "anyhow",
  "codegraph-core",
@@ -625,7 +626,7 @@ dependencies = [
 
 [[package]]
 name = "codegraph-watch"
-version = "0.33.0"
+version = "0.34.0"
 dependencies = [
  "anyhow",
  "codegraph-core",
@@ -3668,6 +3669,16 @@ dependencies = [
  "tree-sitter-language",
 ]
 
+[[package]]
+name = "tree-sitter-solidity"
+version = "1.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4eacf8875b70879f0cb670c60b233ad0b68752d9e1474e6c3ef168eea8a90b25"
+dependencies = [
+ "cc",
+ "tree-sitter-language",
+]
+
 [[package]]
 name = "tree-sitter-swift"
 version = "0.7.3"
diff --git a/README.md b/README.md
index 2d08937..170b1be 100644
--- a/README.md
+++ b/README.md
@@ -439,7 +439,7 @@ Omit `--install` to print to stdout. Full per-shell install paths and notes:
 
 ## What CodeGraph Does (and Doesn't)
 
-**Does:** deterministic code-structure extraction across 33 languages (TypeScript,
+**Does:** deterministic code-structure extraction across 34 languages (TypeScript,
 Python, Go, Rust, Java, C/C++, C#, Vue, Svelte, GDScript, and more — see
 [`docs/languages.md`](docs/languages.md)), cross-file resolution (including
 Godot project graphs), graph traversal, FTS5 search, whole-graph export with
@@ -454,9 +454,9 @@ beyond the fixed `LANGUAGES` set.
 
 ## Supported Languages
 
-CodeGraph supports **33 languages** grouped by extraction depth. Quick overview:
+CodeGraph supports **34 languages** grouped by extraction depth. Quick overview:
 
-- **Tier 1 — Full symbol extraction (24):** TypeScript, TSX, JavaScript, JSX, ArkTS, Python, Go, Rust, Java, C, C++, C#, PHP, Ruby, Swift, Kotlin, Dart, Scala, Lua, Luau, Objective-C, R, GDScript, Pascal.
+- **Tier 1 — Full symbol extraction (25):** TypeScript, TSX, JavaScript, JSX, ArkTS, Python, Go, Rust, Java, C, C++, C#, PHP, Ruby, Swift, Kotlin, Dart, Scala, Lua, Luau, Objective-C, R, Solidity, GDScript, Pascal.
 - **Tier 2 — Embedded / template extraction (6):** Vue, Svelte, Astro, Razor/`.cshtml`, Liquid, XML/MyBatis mapper.
 - **Tier 3 — File-level only (3):** YAML, Twig, Properties.
 
diff --git a/crates/codegraph-bench/fixtures/solidity/IERC20.sol b/crates/codegraph-bench/fixtures/solidity/IERC20.sol
new file mode 100644
index 0000000..2d40b91
--- /dev/null
+++ b/crates/codegraph-bench/fixtures/solidity/IERC20.sol
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+interface IERC20 {
+    function transfer(address to, uint256 value) external returns (bool);
+}
diff --git a/crates/codegraph-bench/fixtures/solidity/Token.sol b/crates/codegraph-bench/fixtures/solidity/Token.sol
new file mode 100644
index 0000000..ceb3788
--- /dev/null
+++ b/crates/codegraph-bench/fixtures/solidity/Token.sol
@@ -0,0 +1,49 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import "./IERC20.sol";
+
+error Unauthorized(address caller);
+
+uint256 constant MAX_SUPPLY = 1000000;
+
+contract Token is IERC20 {
+    uint256 public total;
+
+    event Transfer(address indexed from, uint256 value);
+
+    enum Status {
+        Active,
+        Closed
+    }
+
+    struct Holder {
+        address account;
+        uint256 balance;
+    }
+
+    modifier onlyOwner() {
+        _;
+    }
+
+    constructor() {
+        total = MAX_SUPPLY;
+    }
+
+    fallback() external {
+    }
+
+    receive() external payable {
+    }
+
+    function transfer(address to, uint256 value) public onlyOwner returns (bool) {
+        emit Transfer(to, value);
+        return true;
+    }
+}
+
+library Math {
+    function add(uint256 a, uint256 b) internal pure returns (uint256) {
+        return a + b;
+    }
+}
diff --git a/crates/codegraph-bench/tests/equivalence.rs b/crates/codegraph-bench/tests/equivalence.rs
index 3bee486..af8b299 100644
--- a/crates/codegraph-bench/tests/equivalence.rs
+++ b/crates/codegraph-bench/tests/equivalence.rs
@@ -135,6 +135,27 @@ fn arkts_db_is_self_equivalent_to_arkts_golden() {
     assert_equivalent(&arkts_db(), &arkts_golden_dir()).unwrap();
 }
 
+#[test]
+fn generated_golden_matches_committed_solidity_fixture() {
+    // Guards Solidity extraction (upstream #1170): the `.sol`->Solidity mapping,
+    // contract/library->Class + interface->Interface + struct->Struct +
+    // enum->Enum, synthetic constructor/fallback/receive method names,
+    // state-var/struct-member/event/error->Field, `is`-inheritance->Extends
+    // (resolver promotes to Implements), and emit/modifier-guard call edges.
+    let tempdir = TestDir::new("generated-golden-solidity");
+    write_golden(&solidity_db(), tempdir.path()).unwrap();
+
+    let expected = load_golden(&solidity_golden_dir()).unwrap();
+    let actual = load_golden(tempdir.path()).unwrap();
+
+    diff_canonical(&expected, &actual, None).unwrap();
+}
+
+#[test]
+fn solidity_db_is_self_equivalent_to_solidity_golden() {
+    assert_equivalent(&solidity_db(), &solidity_golden_dir()).unwrap();
+}
+
 #[test]
 fn tier1_node_drift_is_reported() {
     let expected = load_golden(&mini_golden_dir()).unwrap();
@@ -237,6 +258,14 @@ fn arkts_golden_dir() -> PathBuf {
     workspace_root().join("reference/golden/arkts")
 }
 
+fn solidity_db() -> PathBuf {
+    workspace_root().join("reference/golden/solidity/colby.db")
+}
+
+fn solidity_golden_dir() -> PathBuf {
+    workspace_root().join("reference/golden/solidity")
+}
+
 struct TestDir {
     path: PathBuf,
 }
diff --git a/crates/codegraph-core/src/types.rs b/crates/codegraph-core/src/types.rs
index cb266e8..3e8985f 100644
--- a/crates/codegraph-core/src/types.rs
+++ b/crates/codegraph-core/src/types.rs
@@ -49,7 +49,7 @@ pub const EDGE_KIND_STRINGS: [&str; 12] = [
     "decorates",
 ];
 
-pub const LANGUAGE_STRINGS: [&str; 37] = [
+pub const LANGUAGE_STRINGS: [&str; 38] = [
     "typescript",
     "javascript",
     "tsx",
@@ -78,6 +78,7 @@ pub const LANGUAGE_STRINGS: [&str; 37] = [
     "luau",
     "objc",
     "r",
+    "solidity",
     "yaml",
     "twig",
     "xml",
@@ -323,6 +324,8 @@ pub enum Language {
     ObjC,
     #[serde(rename = "r")]
     R,
+    #[serde(rename = "solidity")]
+    Solidity,
     #[serde(rename = "yaml")]
     Yaml,
     #[serde(rename = "twig")]
@@ -344,7 +347,7 @@ pub enum Language {
 }
 
 impl Language {
-    pub const ALL: [Self; 37] = [
+    pub const ALL: [Self; 38] = [
         Self::TypeScript,
         Self::JavaScript,
         Self::Tsx,
@@ -373,6 +376,7 @@ impl Language {
         Self::Luau,
         Self::ObjC,
         Self::R,
+        Self::Solidity,
         Self::Yaml,
         Self::Twig,
         Self::Xml,
@@ -414,6 +418,7 @@ impl Language {
             Self::Luau => "luau",
             Self::ObjC => "objc",
             Self::R => "r",
+            Self::Solidity => "solidity",
             Self::Yaml => "yaml",
             Self::Twig => "twig",
             Self::Xml => "xml",
diff --git a/crates/codegraph-extract/Cargo.toml b/crates/codegraph-extract/Cargo.toml
index 2d3b46d..f1e183c 100644
--- a/crates/codegraph-extract/Cargo.toml
+++ b/crates/codegraph-extract/Cargo.toml
@@ -47,6 +47,7 @@ tree-sitter-r = "1.2.0"
 tree-sitter-ruby = "0.23.1"
 tree-sitter-rust = "0.24.2"
 tree-sitter-scala = "0.26.0"
+tree-sitter-solidity = "1.2.13"
 tree-sitter-swift = "0.7.3"
 tree-sitter-typescript = "0.23.2"
 tree-sitter-xml = "0.7.0"
diff --git a/crates/codegraph-extract/src/engine.rs b/crates/codegraph-extract/src/engine.rs
index 054b157..3131c4d 100644
--- a/crates/codegraph-extract/src/engine.rs
+++ b/crates/codegraph-extract/src/engine.rs
@@ -82,6 +82,7 @@ pub fn builtin_language_for_ext(ext: &str) -> Option<Language> {
         "luau" => Language::Luau,
         "m" | "mm" => Language::ObjC,
         "r" => Language::R,
+        "sol" => Language::Solidity,
         "yml" | "yaml" => Language::Yaml,
         "twig" => Language::Twig,
         "xml" => Language::Xml,
@@ -870,7 +871,7 @@ mod tests {
         assert_eq!(detect_language("s.metal"), Language::Cpp);
         assert_eq!(detect_language("k.cu"), Language::Cpp);
         assert_eq!(detect_language("k.cuh"), Language::Cpp);
-        assert_eq!(Language::ALL.len(), 37);
+        assert_eq!(Language::ALL.len(), 38);
     }
 
     #[test]
@@ -878,6 +879,11 @@ mod tests {
         assert_eq!(detect_language("view.ets"), Language::ArkTs);
     }
 
+    #[test]
+    fn sol_maps_to_solidity() {
+        assert_eq!(detect_language("Token.sol"), Language::Solidity);
+    }
+
     #[test]
     fn plain_ts_stays_typescript() {
         assert_eq!(detect_language("m.ts"), Language::TypeScript);
diff --git a/crates/codegraph-extract/src/lang/mod.rs b/crates/codegraph-extract/src/lang/mod.rs
index 8f8396c..14733d9 100644
--- a/crates/codegraph-extract/src/lang/mod.rs
+++ b/crates/codegraph-extract/src/lang/mod.rs
@@ -24,6 +24,7 @@ mod r;
 mod ruby;
 mod rust;
 mod scala;
+mod solidity;
 mod swift;
 mod tsx;
 mod typescript;
@@ -54,6 +55,7 @@ pub use r::R_SPEC;
 pub use ruby::RUBY_SPEC;
 pub use rust::RUST_SPEC;
 pub use scala::SCALA_SPEC;
+pub use solidity::SOLIDITY_SPEC;
 pub use swift::SWIFT_SPEC;
 pub use tsx::TSX_SPEC;
 pub use typescript::TYPESCRIPT_SPEC;
@@ -83,6 +85,7 @@ pub fn spec_for_language(language: Language) -> Option<&'static dyn LanguageSpec
         Language::Pascal => Some(&PASCAL_SPEC),
         Language::ObjC => Some(&OBJC_SPEC),
         Language::R => Some(&R_SPEC),
+        Language::Solidity => Some(&SOLIDITY_SPEC),
         Language::Gdscript => Some(&GDSCRIPT_SPEC),
         _ => None,
     }
diff --git a/crates/codegraph-extract/src/lang/solidity.rs b/crates/codegraph-extract/src/lang/solidity.rs
new file mode 100644
index 0000000..b465ef7
--- /dev/null
+++ b/crates/codegraph-extract/src/lang/solidity.rs
@@ -0,0 +1,330 @@
+//! Solidity (`.sol`) `LanguageSpec`.
+//!
+//! Extraction-tier port of `upstream extraction/languages/solidity.ts` (commit
+//! `1441933`, #1170). Backed by the `tree-sitter-solidity` grammar crate, this
+//! spec maps the Solidity node kinds to [`codegraph_core::types::NodeKind`]:
+//!
+//! - `contract_declaration` / `library_declaration` → [`NodeKind::Class`],
+//!   `interface_declaration` → [`NodeKind::Interface`],
+//!   `struct_declaration` → [`NodeKind::Struct`],
+//!   `enum_declaration` → [`NodeKind::Enum`];
+//! - `function_definition` / `modifier_definition` are functions/methods, and the
+//!   nameless `constructor_definition` / `fallback_receive_definition` get the
+//!   synthetic names `"constructor"` / `"fallback"` / `"receive"`;
+//! - `is`-inheritance is emitted as `Extends` refs by the walker (D3) — the
+//!   EXISTING resolver promotes those to `Implements` for interface targets, so
+//!   this spec adds NO resolve-tier code.
+//!
+//! The Solidity-only AST shapes the generic dispatcher cannot handle
+//! (direct-`name` fields, bare-text `enum_value`, header `modifier_invocation`,
+//! file-level const, file-level `event`/`error`, and the `user_defined_type`
+//! inheritance ancestor) are handled by the `Language::Solidity`-guarded walker
+//! extensions in [`crate::walker`].
+
+use codegraph_core::types::Language;
+use tree_sitter::{Language as TsLanguage, Node};
+
+use crate::spec::{ImportInfo, LanguageSpec};
+use crate::walker::{child_by_field, node_text};
+
+pub struct SoliditySpec;
+
+pub static SOLIDITY_SPEC: SoliditySpec = SoliditySpec;
+
+impl LanguageSpec for SoliditySpec {
+    fn language(&self) -> Language {
+        Language::Solidity
+    }
+
+    fn tree_sitter_language(&self) -> TsLanguage {
+        tree_sitter_solidity::LANGUAGE.into()
+    }
+
+    fn function_types(&self) -> &'static [&'static str] {
+        &["function_definition", "modifier_definition"]
+    }
+
+    fn class_types(&self) -> &'static [&'static str] {
+        &["contract_declaration", "library_declaration"]
+    }
+
+    fn method_types(&self) -> &'static [&'static str] {
+        &[
+            "function_definition",
+            "modifier_definition",
+            "constructor_definition",
+            "fallback_receive_definition",
+        ]
+    }
+
+    fn interface_types(&self) -> &'static [&'static str] {
+        &["interface_declaration"]
+    }
+
+    fn struct_types(&self) -> &'static [&'static str] {
+        &["struct_declaration"]
+    }
+
+    fn enum_types(&self) -> &'static [&'static str] {
+        &["enum_declaration"]
+    }
+
+    fn enum_member_types(&self) -> &'static [&'static str] {
+        &["enum_value"]
+    }
+
+    fn type_alias_types(&self) -> &'static [&'static str] {
+        &["user_defined_type_definition"]
+    }
+
+    fn import_types(&self) -> &'static [&'static str] {
+        &["import_directive"]
+    }
+
+    fn call_types(&self) -> &'static [&'static str] {
+        &[
+            "call_expression",
+            "emit_statement",
+            "revert_statement",
+            "modifier_invocation",
+        ]
+    }
+
+    fn variable_types(&self) -> &'static [&'static str] {
+        &[
+            "state_variable_declaration",
+            "constant_variable_declaration",
+        ]
+    }
+
+    fn field_types(&self) -> &'static [&'static str] {
+        &[
+            "state_variable_declaration",
+            "struct_member",
+            "event_definition",
+            "error_declaration",
+        ]
+    }
+
+    fn name_field(&self) -> &'static str {
+        "name"
+    }
+
+    fn body_field(&self) -> &'static str {
+        "body"
+    }
+
+    fn params_field(&self) -> &'static str {
+        "parameters"
+    }
+
+    fn return_field(&self) -> &'static str {
+        "return_type"
+    }
+
+    fn resolve_name(&self, node: Node<'_>, _source: &str) -> Option<String> {
+        match node.kind() {
+            "constructor_definition" => Some("constructor".to_string()),
+            "fallback_receive_definition" => {
+                // The keyword is an anonymous child (`fallback` or `receive`);
+                // walk every child and return the first that matches, defaulting
+                // to `fallback` (upstream `fallbackReceiveName`).
+                for i in 0..node.child_count() {
+                    if let Some(child) = node.child(i as u32) {
+                        match child.kind() {
+                            "fallback" => return Some("fallback".to_string()),
+                            "receive" => return Some("receive".to_string()),
+                            _ => {}
+                        }
+                    }
+                }
+                Some("fallback".to_string())
+            }
+            _ => None,
+        }
+    }
+
+    fn get_signature(&self, node: Node<'_>, source: &str) -> Option<String> {
+        // Params are DIRECT children of the decl node, not a `parameters:` field.
+        // Walk the named children and reassemble `(p1, p2) <vis> <mut> <ret>`.
+        let mut params: Vec<String> = Vec::new();
+        let mut visibility: Option<String> = None;
+        let mut mutability: Option<String> = None;
+        let mut return_type: Option<String> = None;
+        for child in node.named_children(&mut node.walk()) {
+            match child.kind() {
+                "parameter" => params.push(node_text(child, source).trim().to_string()),
+                "visibility" => visibility = Some(node_text(child, source).trim().to_string()),
+                "state_mutability" => {
+                    mutability = Some(node_text(child, source).trim().to_string())
+                }
+                "return_type_definition" => {
+                    return_type = Some(node_text(child, source).trim().to_string())
+                }
+                _ => {}
+            }
+        }
+        let mut signature = format!("({})", params.join(", "));
+        if let Some(visibility) = visibility {
+            signature.push(' ');
+            signature.push_str(&visibility);
+        }
+        if let Some(mutability) = mutability {
+            signature.push(' ');
+            signature.push_str(&mutability);
+        }
+        if let Some(return_type) = return_type {
+            signature.push(' ');
+            signature.push_str(&return_type);
+        }
+        Some(signature)
+    }
+
+    fn get_visibility(&self, node: Node<'_>) -> Option<String> {
+        for child in node.named_children(&mut node.walk()) {
+            if child.kind() == "visibility" {
+                let text = child
+                    .child(0)
+                    .map(|kw| kw.kind().to_string())
+                    .unwrap_or_default();
+                return match text.as_str() {
+                    "public" | "external" => Some("public".to_string()),
+                    "private" => Some("private".to_string()),
+                    "internal" => Some("internal".to_string()),
+                    _ => None,
+                };
+            }
+        }
+        None
+    }
+
+    fn is_const(&self, node: Node<'_>) -> bool {
+        node.kind() == "constant_variable_declaration"
+    }
+
+    fn extract_import(&self, node: Node<'_>, source: &str) -> Option<ImportInfo> {
+        let source_node = child_by_field(node, "source")?;
+        let module_name = node_text(source_node, source)
+            .trim()
+            .trim_matches(['\'', '"'])
+            .to_string();
+        if module_name.is_empty() {
+            return None;
+        }
+        Some(ImportInfo {
+            module_name,
+            signature: node_text(node, source).trim().to_string(),
+            handled_refs: false,
+        })
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn parse(src: &str) -> tree_sitter::Tree {
+        let mut parser = tree_sitter::Parser::new();
+        parser
+            .set_language(&tree_sitter_solidity::LANGUAGE.into())
+            .unwrap();
+        parser.parse(src, None).unwrap()
+    }
+
+    fn first_of_kind<'t>(node: Node<'t>, kind: &str) -> Option<Node<'t>> {
+        if node.kind() == kind {
+            return Some(node);
+        }
+        for i in 0..node.named_child_count() {
+            let child = node.named_child(i as u32)?;
+            if let Some(found) = first_of_kind(child, kind) {
+                return Some(found);
+            }
+        }
+        None
+    }
+
+    #[test]
+    fn solidity_class_types() {
+        assert_eq!(
+            SOLIDITY_SPEC.class_types(),
+            ["contract_declaration", "library_declaration"]
+        );
+    }
+
+    #[test]
+    fn solidity_call_types_include_emit_revert_modifier() {
+        assert_eq!(
+            SOLIDITY_SPEC.call_types(),
+            [
+                "call_expression",
+                "emit_statement",
+                "revert_statement",
+                "modifier_invocation"
+            ]
+        );
+    }
+
+    #[test]
+    fn solidity_field_types_include_event_error() {
+        assert_eq!(
+            SOLIDITY_SPEC.field_types(),
+            [
+                "state_variable_declaration",
+                "struct_member",
+                "event_definition",
+                "error_declaration"
+            ]
+        );
+    }
+
+    #[test]
+    fn solidity_parses_contract() {
+        let src = "contract A is B { function f() public {} }";
+        let tree = parse(src);
+        let contract = first_of_kind(tree.root_node(), "contract_declaration")
+            .expect("tree-sitter-solidity parses a contract");
+        let name = child_by_field(contract, "name").expect("contract has a name field");
+        assert_eq!(node_text(name, src), "A");
+        assert!(
+            first_of_kind(tree.root_node(), "inheritance_specifier").is_some(),
+            "the `is B` clause parses as an inheritance_specifier"
+        );
+    }
+
+    #[test]
+    fn solidity_resolve_name_constructor() {
+        let src = "contract C { constructor() {} }";
+        let tree = parse(src);
+        let ctor = first_of_kind(tree.root_node(), "constructor_definition")
+            .expect("parses a constructor_definition");
+        assert_eq!(
+            SOLIDITY_SPEC.resolve_name(ctor, src),
+            Some("constructor".to_string())
+        );
+    }
+
+    #[test]
+    fn solidity_resolve_name_fallback_receive() {
+        let src = "contract C { fallback() external {} receive() external payable {} }";
+        let tree = parse(src);
+        let root = tree.root_node();
+        let mut names = Vec::new();
+        collect_kind(root, "fallback_receive_definition", &mut names, src);
+        assert!(names.contains(&"fallback".to_string()));
+        assert!(names.contains(&"receive".to_string()));
+    }
+
+    fn collect_kind(node: Node<'_>, kind: &str, out: &mut Vec<String>, src: &str) {
+        if node.kind() == kind {
+            if let Some(name) = SOLIDITY_SPEC.resolve_name(node, src) {
+                out.push(name);
+            }
+        }
+        for i in 0..node.named_child_count() {
+            if let Some(child) = node.named_child(i as u32) {
+                collect_kind(child, kind, out, src);
+            }
+        }
+    }
+}
diff --git a/crates/codegraph-extract/src/walker.rs b/crates/codegraph-extract/src/walker.rs
index 3d4805e..328e548 100644
--- a/crates/codegraph-extract/src/walker.rs
+++ b/crates/codegraph-extract/src/walker.rs
@@ -228,10 +228,39 @@ impl<'a, 'tree> TreeSitterWalker<'a, 'tree> {
             Language::R => self.visit_r_node(node),
             Language::Gdscript => self.visit_gdscript_node(node),
             Language::Cpp => self.visit_cpp_node(node),
+            Language::Solidity => self.visit_solidity_node(node),
             _ => false,
         }
     }
 
+    fn visit_solidity_node(&mut self, node: SyntaxNode<'tree>) -> bool {
+        // #1170 — upstream `solidityExtractor.visitNode` emits a `field` node for
+        // `event_definition` / `error_declaration` UNCONDITIONALLY, file-level
+        // included. The generic field dispatch is class-like-scope-gated, so a
+        // FREE (top-level) event/error is dropped. Emit the Field here only when
+        // NOT inside a class-like scope; inside a contract, return false so the D5
+        // field path owns it (no double-emit).
+        if matches!(node.kind(), "event_definition" | "error_declaration")
+            && !self.is_inside_class_like_node()
+        {
+            if let Some(name_node) = child_by_field(node, "name") {
+                let name = node_text(name_node, self.source);
+                let signature = property_or_field_signature(node, &name, self.source);
+                self.create_node(
+                    NodeKind::Field,
+                    &name,
+                    node,
+                    NodeExtra {
+                        signature,
+                        ..NodeExtra::default()
+                    },
+                );
+            }
+            return true;
+        }
+        false
+    }
+
     fn visit_cpp_node(&mut self, node: SyntaxNode<'tree>) -> bool {
         if node.kind() != "namespace_definition" {
             return false;
@@ -1441,6 +1470,17 @@ impl<'a, 'tree> TreeSitterWalker<'a, 'tree> {
                 }
             }
         }
+        // #1170 — Solidity `enum_value` is a LEAF named node (no name field, no id
+        // child); its own text is the member name. Emit from the node text when
+        // the name-field / id-child paths above found nothing.
+        if node.kind() == "enum_value" {
+            self.create_node(
+                NodeKind::EnumMember,
+                &node_text(node, self.source),
+                node,
+                NodeExtra::default(),
+            );
+        }
     }
 
     fn extract_type_alias(&mut self, node: SyntaxNode<'tree>) {
@@ -1532,6 +1572,29 @@ impl<'a, 'tree> TreeSitterWalker<'a, 'tree> {
             self.extract_go_variable(node);
             return;
         }
+        if self.spec.language() == Language::Solidity {
+            // #1170 — file-scope `constant_variable_declaration` (`uint256 constant
+            // MAX = 100;`) carries a direct `name` field. Emit a Constant (const)
+            // else Variable. `state_variable_declaration` is always a contract
+            // member (handled as a Field), so it never reaches this top-level arm.
+            if let Some(name_node) = child_by_field(node, "name") {
+                let kind = if self.spec.is_const(node) {
+                    NodeKind::Constant
+                } else {
+                    NodeKind::Variable
+                };
+                self.create_node(
+                    kind,
+                    &node_text(name_node, self.source),
+                    node,
+                    NodeExtra {
+                        docstring: self.preceding_docstring(node),
+                        ..NodeExtra::default()
+                    },
+                );
+            }
+            return;
+        }
         if !matches!(
             self.spec.language(),
             Language::TypeScript | Language::Tsx | Language::JavaScript | Language::Jsx
@@ -1758,6 +1821,29 @@ impl<'a, 'tree> TreeSitterWalker<'a, 'tree> {
 
     fn extract_field(&mut self, node: SyntaxNode<'tree>) {
         let declarators = field_declarators(node).collect::<Vec<_>>();
+        if declarators.is_empty() && self.spec.language() == Language::Solidity {
+            // #1170 — Solidity `state_variable_declaration` / `struct_member` /
+            // `event_definition` / `error_declaration` carry the name in a DIRECT
+            // `name` field, not a `variable_declarator`, so `field_declarators`
+            // finds nothing. Emit one Field from the `name` field.
+            if let Some(name_node) = child_by_field(node, "name") {
+                let name = node_text(name_node, self.source);
+                let signature = property_or_field_signature(node, &name, self.source);
+                if let Some(field_node) = self.create_node(
+                    NodeKind::Field,
+                    &name,
+                    node,
+                    NodeExtra {
+                        signature,
+                        visibility: self.spec.get_visibility(node),
+                        ..NodeExtra::default()
+                    },
+                ) {
+                    self.extract_type_annotations(node, &field_node.id);
+                }
+            }
+            return;
+        }
         if declarators.is_empty() && self.spec.language() == Language::Php {
             for elem in node
                 .named_children(&mut node.walk())
@@ -2440,6 +2526,29 @@ impl<'a, 'tree> TreeSitterWalker<'a, 'tree> {
                         type_id,
                     );
                 }
+                // #1170 — Solidity `contract Token is IERC20, Ownable`: the
+                // inheritance_specifier's `ancestor` field is a `user_defined_type`
+                // (not the Swift `user_type`), whose LAST `identifier` descendant is
+                // the base name. Shape-guarded on `user_defined_type` so the Swift
+                // path above is untouched. The resolver promotes Extends→Implements
+                // for interface targets.
+                if let Some(base) = child
+                    .named_children(&mut child.walk())
+                    .find(|c| c.kind() == "user_defined_type")
+                {
+                    if let Some(name_node) = base
+                        .named_children(&mut base.walk())
+                        .filter(|c| c.kind() == "identifier")
+                        .last()
+                    {
+                        self.push_ref(
+                            class_id,
+                            &node_text(name_node, self.source),
+                            EdgeKind::Extends,
+                            name_node,
+                        );
+                    }
+                }
             }
             if child.kind() == "class_heritage" {
                 self.extract_inheritance(child, class_id);
@@ -2504,6 +2613,23 @@ impl<'a, 'tree> TreeSitterWalker<'a, 'tree> {
     fn extract_decorators_for(&mut self, decl_node: SyntaxNode<'tree>, decorated_id: &str) {
         for child in decl_node.named_children(&mut decl_node.walk()) {
             self.consider_decorator(child, decorated_id);
+            // #1170 — a Solidity header `modifier_invocation` (`function f() onlyOwner`,
+            // `constructor() ERC20(...)`) is a named child of the decl outside the
+            // `body` field, so the body walker never reaches it. Emit a Calls ref
+            // (NOT Decorates) named by its first identifier so flow traversal rides
+            // the modifier guard / base-constructor chain. Shape-guarded so other
+            // languages are untouched.
+            if child.kind() == "modifier_invocation" {
+                if let Some(ident) = child
+                    .named_children(&mut child.walk())
+                    .find(|c| c.kind() == "identifier")
+                {
+                    let name = node_text(ident, self.source);
+                    if !name.is_empty() {
+                        self.push_ref(decorated_id, &name, EdgeKind::Calls, child);
+                    }
+                }
+            }
             // tree-sitter.ts:2940-2948 — Java/Kotlin/C#/Swift annotations and
             // attributes nest INSIDE a `modifiers` child; descend one level so
             // they are not silently dropped.
@@ -3541,6 +3667,134 @@ class Model {}
         assert!(has_ref(&refs, EdgeKind::Calls, "helper"));
     }
 
+    // ---- Solidity (.sol) extraction tier (#1170) ----
+
+    #[test]
+    fn solidity_contract_is_records_extends() {
+        let src = "contract MyToken is Token, IERC20 { }";
+        let (_, refs) = run("A.sol", src, Language::Solidity);
+        assert!(has_ref(&refs, EdgeKind::Extends, "Token"));
+        assert!(has_ref(&refs, EdgeKind::Extends, "IERC20"));
+    }
+
+    #[test]
+    fn solidity_state_var_and_struct_member_are_fields() {
+        let src = r#"
+contract C {
+    uint256 public total;
+    struct S { uint256 a; }
+}
+"#;
+        let (nodes, _) = run("C.sol", src, Language::Solidity);
+        assert!(has_node(&nodes, NodeKind::Field, "total"));
+        assert!(has_node(&nodes, NodeKind::Field, "a"));
+    }
+
+    #[test]
+    fn solidity_event_error_are_field_nodes() {
+        let src = r#"
+contract C {
+    event Transfer(address to, uint256 v);
+    error Bad(uint256 code);
+}
+"#;
+        let (nodes, _) = run("C.sol", src, Language::Solidity);
+        assert!(has_node(&nodes, NodeKind::Field, "Transfer"));
+        assert!(has_node(&nodes, NodeKind::Field, "Bad"));
+    }
+
+    #[test]
+    fn solidity_enum_values_are_members() {
+        let src = "contract C { enum Status { Active, Closed } }";
+        let (nodes, _) = run("C.sol", src, Language::Solidity);
+        assert!(has_node(&nodes, NodeKind::EnumMember, "Active"));
+        assert!(has_node(&nodes, NodeKind::EnumMember, "Closed"));
+    }
+
+    #[test]
+    fn solidity_modifier_guard_is_call() {
+        let src = r#"
+contract C {
+    modifier onlyOwner() { _; }
+    function withdraw() public onlyOwner { }
+}
+"#;
+        let (_, refs) = run("C.sol", src, Language::Solidity);
+        assert!(has_ref(&refs, EdgeKind::Calls, "onlyOwner"));
+        assert!(
+            !refs
+                .iter()
+                .any(|r| r.reference_name == "onlyOwner"
+                    && r.reference_kind == EdgeKind::Decorates),
+            "modifier guard must be a Calls ref, not Decorates"
+        );
+    }
+
+    #[test]
+    fn solidity_top_level_constant_is_constant() {
+        let src = "uint256 constant MAX = 100;";
+        let (nodes, _) = run("C.sol", src, Language::Solidity);
+        assert!(has_node(&nodes, NodeKind::Constant, "MAX"));
+    }
+
+    #[test]
+    fn solidity_file_level_event_error_are_fields() {
+        let src = r#"
+event Bar(uint256 x);
+error Foo(address a);
+"#;
+        let (nodes, _) = run("free.sol", src, Language::Solidity);
+        assert!(has_node(&nodes, NodeKind::Field, "Bar"));
+        assert!(has_node(&nodes, NodeKind::Field, "Foo"));
+    }
+
+    #[test]
+    fn solidity_top_level_event_error_do_not_double_emit_inside_contract() {
+        let src = "contract C { event E(uint256 x); }";
+        let (nodes, _) = run("C.sol", src, Language::Solidity);
+        let count = nodes
+            .iter()
+            .filter(|n| n.kind == NodeKind::Field && n.name == "E")
+            .count();
+        assert_eq!(count, 1, "in-contract event must emit exactly one Field");
+    }
+
+    #[test]
+    fn solidity_extracts_contract_interface_struct_fn_field_event_import_call() {
+        let src = r#"
+import "./IERC20.sol";
+
+interface IERC20 {
+    function transfer(address to, uint256 v) external returns (bool);
+}
+
+contract Token is IERC20 {
+    event Transfer(address to, uint256 v);
+    modifier onlyOwner() { _; }
+    constructor() { }
+    function transfer(address to, uint256 v) public onlyOwner returns (bool) {
+        emit Transfer(to, v);
+        return true;
+    }
+}
+
+library Math {
+    function add(uint256 a, uint256 b) internal pure returns (uint256) { return a + b; }
+}
+"#;
+        let (nodes, refs) = run("Token.sol", src, Language::Solidity);
+        assert!(has_node(&nodes, NodeKind::Class, "Token"));
+        assert!(has_node(&nodes, NodeKind::Interface, "IERC20"));
+        assert!(has_node(&nodes, NodeKind::Class, "Math"));
+        assert!(has_node(&nodes, NodeKind::Method, "transfer"));
+        assert!(has_node(&nodes, NodeKind::Method, "constructor"));
+        assert!(has_node(&nodes, NodeKind::Field, "Transfer"));
+        assert!(has_node(&nodes, NodeKind::Import, "./IERC20.sol"));
+        assert!(has_ref(&refs, EdgeKind::Extends, "IERC20"));
+        assert!(has_ref(&refs, EdgeKind::Calls, "onlyOwner"));
+        assert!(has_ref(&refs, EdgeKind::Calls, "Transfer"));
+    }
+
     // ---- Lua / Luau require variants ----
 
     #[test]
diff --git a/crates/codegraph-store/src/queries.rs b/crates/codegraph-store/src/queries.rs
index f6bdcc3..6e16dc1 100644
--- a/crates/codegraph-store/src/queries.rs
+++ b/crates/codegraph-store/src/queries.rs
@@ -1524,6 +1524,7 @@ fn parse_language(value: String) -> rusqlite::Result<Language> {
         "luau" => Language::Luau,
         "objc" => Language::ObjC,
         "r" => Language::R,
+        "solidity" => Language::Solidity,
         "yaml" => Language::Yaml,
         "twig" => Language::Twig,
         "xml" => Language::Xml,
diff --git a/docs/equivalence.md b/docs/equivalence.md
index 9936318..00a8b6a 100644
--- a/docs/equivalence.md
+++ b/docs/equivalence.md
@@ -406,6 +406,56 @@ The `generated_golden_matches_committed_arkts_fixture` and
 `arkts_db_is_self_equivalent_to_arkts_golden` tests in
 `crates/codegraph-bench/tests/equivalence.rs` enforce byte-stability.
 
+### Solidity fixture
+
+An eighth golden fixture, `reference/golden/solidity/`, guards Solidity (`.sol`)
+extraction (upstream #1170 / `1441933`). Solidity is a **new `Language::Solidity`
+variant** backed by a **dedicated `tree-sitter-solidity` grammar**. `.sol` maps to
+`Language::Solidity`. The corpus (`crates/codegraph-bench/fixtures/solidity/`) has
+an `IERC20.sol` interface and a `Token.sol` that imports it, declares a file-level
+`error` and a file-level `constant`, and a `contract Token is IERC20` carrying a
+state variable, an `event`, an `enum`, a `struct`, a `modifier`, a `constructor`,
+`fallback`/`receive`, and a `transfer` function guarded by the modifier that
+`emit`s the event, plus a `library Math`. What it guards:
+
+- both `.sol` files with `"language": "solidity"`;
+- `contract Token` / `library Math` as `NodeKind::Class`, `interface IERC20` as
+  `NodeKind::Interface`, `struct Holder` as `NodeKind::Struct`, `enum Status` as
+  `NodeKind::Enum` with its `Active`/`Closed` members (bare-text `enum_value`);
+- functions/modifiers/methods, including the synthetic `constructor` / `fallback`
+  / `receive` method names (nameless grammar nodes);
+- state variable / struct member / `event` / `error` as `NodeKind::Field` name
+  nodes (direct-`name` field, no `variable_declarator`), including the file-level
+  `Unauthorized` error and the file-level `MAX_SUPPLY` constant;
+- the `./IERC20.sol` import node + `imports` edge;
+- `is`-inheritance emitted as an `Extends` ref, promoted by the EXISTING resolver
+  to an `Implements` edge `Token → IERC20` (interface target, present in-corpus);
+- `emit`/header `modifier_invocation` `Calls` edges (`transfer → Transfer`,
+  `transfer → onlyOwner`), resolved to same-file targets.
+
+Because the fixture is fully self-contained, every ref resolves in-corpus, so
+`refs.json` is empty and `edges.json` holds only RESOLVED edges — the expected
+post-resolution state. No `FrameworkResolver` impl is involved; the
+`Extends → Implements` promotion is the same path Java/C# use
+(`resolver.rs:1231-1247`). Adding the variant is byte-neutral for
+`colby.schema.sql` (language is a stored TEXT value, not DDL) and for the seven
+existing goldens (none holds a `.sol` file).
+
+Regenerate reproducibly (identical recipe to the ArkTS fixture, substituting
+`solidity`):
+
+```bash
+rm -rf /tmp/cg-fixture-solidity && cp -r crates/codegraph-bench/fixtures/solidity /tmp/cg-fixture-solidity
+cargo build --release -p codegraph-rs
+CODEGRAPH_NO_DAEMON=1 CODEGRAPH_NO_WATCH=1 ./target/release/codegraph init /tmp/cg-fixture-solidity
+cp /tmp/cg-fixture-solidity/.codegraph/codegraph.db reference/golden/solidity/colby.db
+cargo run -p codegraph-bench --bin bench -- --gen-golden reference/golden/solidity/colby.db reference/golden/solidity
+```
+
+The `generated_golden_matches_committed_solidity_fixture` and
+`solidity_db_is_self_equivalent_to_solidity_golden` tests in
+`crates/codegraph-bench/tests/equivalence.rs` enforce byte-stability.
+
 ### KNOWN_DIFFS.md format
 
 Tier-3 differences are allowlisted by grep-able lines in repo-root
diff --git a/docs/languages.md b/docs/languages.md
index 630a494..4a18e7e 100644
--- a/docs/languages.md
+++ b/docs/languages.md
@@ -4,7 +4,7 @@ CodeGraph extracts code structure deterministically using tree-sitter grammars a
 embedded extractors. No AI, vectors, or embeddings are involved. The output is byte-stable
 across runs.
 
-**33 concrete languages** are supported, grouped into three extraction tiers based on what
+**34 concrete languages** are supported, grouped into three extraction tiers based on what
 the extractor produces.
 
 > **Note on TypeScript/JavaScript variants:** `typescript` and `tsx`, and `javascript` and
@@ -14,38 +14,39 @@ the extractor produces.
 
 ---
 
-## Tier 1 — Full symbol extraction (24 languages)
+## Tier 1 — Full symbol extraction (25 languages)
 
 Tree-sitter parses the file and extracts all symbols (functions, classes, structs, methods,
 variables, imports, etc.) plus call and dependency edges. This is the richest extraction
 level.
 
-| Language    | Extensions                                  | Extraction                | Notes                                                                                                                                                                                                             |
-| ----------- | ------------------------------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| TypeScript  | `.ts` `.mts` `.cts`                         | Full tree-sitter          |                                                                                                                                                                                                                   |
-| TSX         | `.tsx`                                      | Full tree-sitter          | TypeScript grammar, JSX syntax                                                                                                                                                                                    |
-| JavaScript  | `.js` `.mjs` `.cjs` `.xsjs` `.xsjslib`      | Full tree-sitter          |                                                                                                                                                                                                                   |
-| JSX         | `.jsx`                                      | Full tree-sitter          | JavaScript grammar, JSX syntax                                                                                                                                                                                    |
-| ArkTS       | `.ets`                                      | Full tree-sitter          | HarmonyOS / OpenHarmony; `tree-sitter-arkts` grammar. `@Component struct` → struct symbol. ArkUI dynamic-dispatch bridges deferred. Plain `.ts` stays TypeScript                                                  |
-| Python      | `.py` `.pyw`                                | Full tree-sitter          |                                                                                                                                                                                                                   |
-| Go          | `.go`                                       | Full tree-sitter          |                                                                                                                                                                                                                   |
-| Rust        | `.rs`                                       | Full tree-sitter          |                                                                                                                                                                                                                   |
-| Java        | `.java`                                     | Full tree-sitter          |                                                                                                                                                                                                                   |
-| C           | `.c` `.h`                                   | Full tree-sitter          | `.h` may be promoted to C++ or Objective-C by heuristics                                                                                                                                                          |
-| C++         | `.cpp` `.cc` `.cxx` `.hpp` `.hxx`           | Full tree-sitter          |                                                                                                                                                                                                                   |
-| C#          | `.cs`                                       | Full tree-sitter          |                                                                                                                                                                                                                   |
-| PHP         | `.php` `.module` `.install` `.theme` `.inc` | Full tree-sitter          |                                                                                                                                                                                                                   |
-| Ruby        | `.rb` `.rake`                               | Full tree-sitter          |                                                                                                                                                                                                                   |
-| Swift       | `.swift`                                    | Full tree-sitter          |                                                                                                                                                                                                                   |
-| Kotlin      | `.kt` `.kts`                                | Full tree-sitter          |                                                                                                                                                                                                                   |
-| Dart        | `.dart`                                     | Full tree-sitter          |                                                                                                                                                                                                                   |
-| Scala       | `.scala` `.sc`                              | Full tree-sitter          |                                                                                                                                                                                                                   |
-| Lua         | `.lua`                                      | Full tree-sitter          |                                                                                                                                                                                                                   |
-| Luau        | `.luau`                                     | Full tree-sitter          | Roblox Luau dialect                                                                                                                                                                                               |
-| Objective-C | `.m` `.mm`                                  | Full tree-sitter          |                                                                                                                                                                                                                   |
-| R           | `.r`                                        | Full tree-sitter          |                                                                                                                                                                                                                   |
-| GDScript    | `.gd`                                       | Full tree-sitter          | Godot scripting; extracts functions, classes, enums, variables, signals, extends, preload. Dynamic dispatch edges (connect/get_node/$/%/call/group) added by the Godot resolver — see [`docs/godot.md`](godot.md) |
-| Pascal      | `.pas` `.dpr` `.dpk` `.lpr` `.dfm` `.fmx`   | Full tree-sitter / custom | `.dfm`/`.fmx` form files use a custom path                                                                                                                                                                        |
+| Language    | Extensions                                  | Extraction                | Notes                                                                                                                                                                                                                         |
+| ----------- | ------------------------------------------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| TypeScript  | `.ts` `.mts` `.cts`                         | Full tree-sitter          |                                                                                                                                                                                                                               |
+| TSX         | `.tsx`                                      | Full tree-sitter          | TypeScript grammar, JSX syntax                                                                                                                                                                                                |
+| JavaScript  | `.js` `.mjs` `.cjs` `.xsjs` `.xsjslib`      | Full tree-sitter          |                                                                                                                                                                                                                               |
+| JSX         | `.jsx`                                      | Full tree-sitter          | JavaScript grammar, JSX syntax                                                                                                                                                                                                |
+| ArkTS       | `.ets`                                      | Full tree-sitter          | HarmonyOS / OpenHarmony; `tree-sitter-arkts` grammar. `@Component struct` → struct symbol. ArkUI dynamic-dispatch bridges deferred. Plain `.ts` stays TypeScript                                                              |
+| Python      | `.py` `.pyw`                                | Full tree-sitter          |                                                                                                                                                                                                                               |
+| Go          | `.go`                                       | Full tree-sitter          |                                                                                                                                                                                                                               |
+| Rust        | `.rs`                                       | Full tree-sitter          |                                                                                                                                                                                                                               |
+| Java        | `.java`                                     | Full tree-sitter          |                                                                                                                                                                                                                               |
+| C           | `.c` `.h`                                   | Full tree-sitter          | `.h` may be promoted to C++ or Objective-C by heuristics                                                                                                                                                                      |
+| C++         | `.cpp` `.cc` `.cxx` `.hpp` `.hxx`           | Full tree-sitter          |                                                                                                                                                                                                                               |
+| C#          | `.cs`                                       | Full tree-sitter          |                                                                                                                                                                                                                               |
+| PHP         | `.php` `.module` `.install` `.theme` `.inc` | Full tree-sitter          |                                                                                                                                                                                                                               |
+| Ruby        | `.rb` `.rake`                               | Full tree-sitter          |                                                                                                                                                                                                                               |
+| Swift       | `.swift`                                    | Full tree-sitter          |                                                                                                                                                                                                                               |
+| Kotlin      | `.kt` `.kts`                                | Full tree-sitter          |                                                                                                                                                                                                                               |
+| Dart        | `.dart`                                     | Full tree-sitter          |                                                                                                                                                                                                                               |
+| Scala       | `.scala` `.sc`                              | Full tree-sitter          |                                                                                                                                                                                                                               |
+| Lua         | `.lua`                                      | Full tree-sitter          |                                                                                                                                                                                                                               |
+| Luau        | `.luau`                                     | Full tree-sitter          | Roblox Luau dialect                                                                                                                                                                                                           |
+| Objective-C | `.m` `.mm`                                  | Full tree-sitter          |                                                                                                                                                                                                                               |
+| R           | `.r`                                        | Full tree-sitter          |                                                                                                                                                                                                                               |
+| Solidity    | `.sol`                                      | Full tree-sitter          | `tree-sitter-solidity` grammar; contracts/libraries/interfaces, structs, enums, modifiers, events, errors; `is`-inheritance → Extends (resolver promotes to Implements for interfaces); emit/revert/modifier-guard call edges |
+| GDScript    | `.gd`                                       | Full tree-sitter          | Godot scripting; extracts functions, classes, enums, variables, signals, extends, preload. Dynamic dispatch edges (connect/get_node/$/%/call/group) added by the Godot resolver — see [`docs/godot.md`](godot.md)             |
+| Pascal      | `.pas` `.dpr` `.dpk` `.lpr` `.dfm` `.fmx`   | Full tree-sitter / custom | `.dfm`/`.fmx` form files use a custom path                                                                                                                                                                                    |
 
 ---
 
diff --git a/reference/golden/solidity/colby.db b/reference/golden/solidity/colby.db
new file mode 100644
index 0000000..a786dde
Binary files /dev/null and b/reference/golden/solidity/colby.db differ
diff --git a/reference/golden/solidity/edges.json b/reference/golden/solidity/edges.json
new file mode 100644
index 0000000..e638d9d
--- /dev/null
+++ b/reference/golden/solidity/edges.json
@@ -0,0 +1,239 @@
+[
+  {
+    "col": 0,
+    "kind": "imports",
+    "line": 4,
+    "metadata": {
+      "confidence": 0.7,
+      "resolvedBy": "file-path"
+    },
+    "provenance": null,
+    "source": "file:Token.sol",
+    "target": "file:IERC20.sol"
+  },
+  {
+    "col": 18,
+    "kind": "implements",
+    "line": 10,
+    "metadata": {
+      "confidence": 0.9,
+      "resolvedBy": "exact-match"
+    },
+    "provenance": null,
+    "source": "class:cbe42c3edda8b791e2f65c50de43bf90",
+    "target": "interface:cc05f27c43c35cc4ab3d86bb6f06872c"
+  },
+  {
+    "col": 56,
+    "kind": "calls",
+    "line": 39,
+    "metadata": {
+      "confidence": 0.9,
+      "resolvedBy": "exact-match"
+    },
+    "provenance": null,
+    "source": "method:1c8a7b45450c9d4eed6e478286852ad3",
+    "target": "method:d56cce424b1c30328b00f0b981df8233"
+  },
+  {
+    "col": 8,
+    "kind": "calls",
+    "line": 40,
+    "metadata": {
+      "confidence": 0.9,
+      "resolvedBy": "exact-match"
+    },
+    "provenance": null,
+    "source": "method:1c8a7b45450c9d4eed6e478286852ad3",
+    "target": "field:55aa8c4f588a7ddd89448639dd5cc613"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "class:6a57b726319c85287cd5966662055efd",
+    "target": "method:01522a942d17de1001d5a8e65bbe316a"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "class:cbe42c3edda8b791e2f65c50de43bf90",
+    "target": "enum:18a0bcec3e0b273f8ca328dc05fc7c62"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "class:cbe42c3edda8b791e2f65c50de43bf90",
+    "target": "field:55aa8c4f588a7ddd89448639dd5cc613"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "class:cbe42c3edda8b791e2f65c50de43bf90",
+    "target": "field:620dcea68e269e5d25084e930b381daa"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "class:cbe42c3edda8b791e2f65c50de43bf90",
+    "target": "method:069c78f8d4d5c513593c3c944014a0b0"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "class:cbe42c3edda8b791e2f65c50de43bf90",
+    "target": "method:1c8a7b45450c9d4eed6e478286852ad3"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "class:cbe42c3edda8b791e2f65c50de43bf90",
+    "target": "method:46d4bf9937e477f5bd270bb05b6696f0"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "class:cbe42c3edda8b791e2f65c50de43bf90",
+    "target": "method:768b3877a930b3ee9c3b24466c601f38"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "class:cbe42c3edda8b791e2f65c50de43bf90",
+    "target": "method:d56cce424b1c30328b00f0b981df8233"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "class:cbe42c3edda8b791e2f65c50de43bf90",
+    "target": "struct:6879c4fba147cd44c382552884de5563"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "enum:18a0bcec3e0b273f8ca328dc05fc7c62",
+    "target": "enum_member:433d4857330d95a2c514d9a3e682a08b"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "enum:18a0bcec3e0b273f8ca328dc05fc7c62",
+    "target": "enum_member:e933e9c8a19aefff4e435ab2db55b0ae"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "file:IERC20.sol",
+    "target": "interface:cc05f27c43c35cc4ab3d86bb6f06872c"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "file:Token.sol",
+    "target": "class:6a57b726319c85287cd5966662055efd"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "file:Token.sol",
+    "target": "class:cbe42c3edda8b791e2f65c50de43bf90"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "file:Token.sol",
+    "target": "constant:2e4331f08e0c9bb2d6c0c9de9f696935"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "file:Token.sol",
+    "target": "field:4df8f64fd61911a088da5b8596f81045"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "file:Token.sol",
+    "target": "import:a2e94e572fe1823c82b046dd0a3030d9"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "interface:cc05f27c43c35cc4ab3d86bb6f06872c",
+    "target": "method:14e6265384fe621344552d55e10f8466"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "struct:6879c4fba147cd44c382552884de5563",
+    "target": "field:ee915f379fbf10ac1ed613b353ccabc0"
+  },
+  {
+    "col": null,
+    "kind": "contains",
+    "line": null,
+    "metadata": null,
+    "provenance": null,
+    "source": "struct:6879c4fba147cd44c382552884de5563",
+    "target": "field:fcc8c476605ce6c1cdd89fdf53a1f4fc"
+  }
+]
diff --git a/reference/golden/solidity/files.json b/reference/golden/solidity/files.json
new file mode 100644
index 0000000..d14c806
--- /dev/null
+++ b/reference/golden/solidity/files.json
@@ -0,0 +1,18 @@
+[
+  {
+    "content_hash": "bef3d1355e28323c5eaeeac93fd3693297706de47dd276566eee9d64a4568d6f",
+    "errors": null,
+    "language": "solidity",
+    "node_count": 3,
+    "path": "IERC20.sol",
+    "size": 152
+  },
+  {
+    "content_hash": "c8976b8cc5a7ea552da5c19efd79afa395873bd8a1253ebe9282b538e4c9a8e3",
+    "errors": null,
+    "language": "solidity",
+    "node_count": 20,
+    "path": "Token.sol",
+    "size": 841
+  }
+]
diff --git a/reference/golden/solidity/nodes.json b/reference/golden/solidity/nodes.json
new file mode 100644
index 0000000..9e4e732
--- /dev/null
+++ b/reference/golden/solidity/nodes.json
@@ -0,0 +1,508 @@
+[
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 1,
+    "end_line": 49,
+    "file_path": "Token.sol",
+    "id": "class:6a57b726319c85287cd5966662055efd",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "class",
+    "language": "solidity",
+    "name": "Math",
+    "qualified_name": "Math",
+    "return_type": null,
+    "signature": null,
+    "start_column": 0,
+    "start_line": 45,
+    "type_parameters": null,
+    "visibility": null
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 1,
+    "end_line": 43,
+    "file_path": "Token.sol",
+    "id": "class:cbe42c3edda8b791e2f65c50de43bf90",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "class",
+    "language": "solidity",
+    "name": "Token",
+    "qualified_name": "Token",
+    "return_type": null,
+    "signature": null,
+    "start_column": 0,
+    "start_line": 10,
+    "type_parameters": null,
+    "visibility": null
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 38,
+    "end_line": 8,
+    "file_path": "Token.sol",
+    "id": "constant:2e4331f08e0c9bb2d6c0c9de9f696935",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "constant",
+    "language": "solidity",
+    "name": "MAX_SUPPLY",
+    "qualified_name": "MAX_SUPPLY",
+    "return_type": null,
+    "signature": null,
+    "start_column": 0,
+    "start_line": 8,
+    "type_parameters": null,
+    "visibility": null
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 5,
+    "end_line": 18,
+    "file_path": "Token.sol",
+    "id": "enum:18a0bcec3e0b273f8ca328dc05fc7c62",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "enum",
+    "language": "solidity",
+    "name": "Status",
+    "qualified_name": "Token::Status",
+    "return_type": null,
+    "signature": null,
+    "start_column": 4,
+    "start_line": 15,
+    "type_parameters": null,
+    "visibility": null
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 14,
+    "end_line": 16,
+    "file_path": "Token.sol",
+    "id": "enum_member:433d4857330d95a2c514d9a3e682a08b",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "enum_member",
+    "language": "solidity",
+    "name": "Active",
+    "qualified_name": "Token::Status::Active",
+    "return_type": null,
+    "signature": null,
+    "start_column": 8,
+    "start_line": 16,
+    "type_parameters": null,
+    "visibility": null
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 14,
+    "end_line": 17,
+    "file_path": "Token.sol",
+    "id": "enum_member:e933e9c8a19aefff4e435ab2db55b0ae",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "enum_member",
+    "language": "solidity",
+    "name": "Closed",
+    "qualified_name": "Token::Status::Closed",
+    "return_type": null,
+    "signature": null,
+    "start_column": 8,
+    "start_line": 17,
+    "type_parameters": null,
+    "visibility": null
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 35,
+    "end_line": 6,
+    "file_path": "Token.sol",
+    "id": "field:4df8f64fd61911a088da5b8596f81045",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "field",
+    "language": "solidity",
+    "name": "Unauthorized",
+    "qualified_name": "Unauthorized",
+    "return_type": null,
+    "signature": "address caller Unauthorized",
+    "start_column": 0,
+    "start_line": 6,
+    "type_parameters": null,
+    "visibility": null
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 56,
+    "end_line": 13,
+    "file_path": "Token.sol",
+    "id": "field:55aa8c4f588a7ddd89448639dd5cc613",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "field",
+    "language": "solidity",
+    "name": "Transfer",
+    "qualified_name": "Token::Transfer",
+    "return_type": null,
+    "signature": "address indexed from Transfer",
+    "start_column": 4,
+    "start_line": 13,
+    "type_parameters": null,
+    "visibility": null
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 25,
+    "end_line": 11,
+    "file_path": "Token.sol",
+    "id": "field:620dcea68e269e5d25084e930b381daa",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "field",
+    "language": "solidity",
+    "name": "total",
+    "qualified_name": "Token::total",
+    "return_type": null,
+    "signature": "uint256 total",
+    "start_column": 4,
+    "start_line": 11,
+    "type_parameters": null,
+    "visibility": "public"
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 24,
+    "end_line": 22,
+    "file_path": "Token.sol",
+    "id": "field:ee915f379fbf10ac1ed613b353ccabc0",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "field",
+    "language": "solidity",
+    "name": "balance",
+    "qualified_name": "Token::Holder::balance",
+    "return_type": null,
+    "signature": "uint256 balance",
+    "start_column": 8,
+    "start_line": 22,
+    "type_parameters": null,
+    "visibility": null
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 24,
+    "end_line": 21,
+    "file_path": "Token.sol",
+    "id": "field:fcc8c476605ce6c1cdd89fdf53a1f4fc",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "field",
+    "language": "solidity",
+    "name": "account",
+    "qualified_name": "Token::Holder::account",
+    "return_type": null,
+    "signature": "address account",
+    "start_column": 8,
+    "start_line": 21,
+    "type_parameters": null,
+    "visibility": null
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 0,
+    "end_line": 7,
+    "file_path": "IERC20.sol",
+    "id": "file:IERC20.sol",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "file",
+    "language": "solidity",
+    "name": "IERC20.sol",
+    "qualified_name": "IERC20.sol",
+    "return_type": null,
+    "signature": null,
+    "start_column": 0,
+    "start_line": 1,
+    "type_parameters": null,
+    "visibility": null
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 0,
+    "end_line": 50,
+    "file_path": "Token.sol",
+    "id": "file:Token.sol",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "file",
+    "language": "solidity",
+    "name": "Token.sol",
+    "qualified_name": "Token.sol",
+    "return_type": null,
+    "signature": null,
+    "start_column": 0,
+    "start_line": 1,
+    "type_parameters": null,
+    "visibility": null
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 22,
+    "end_line": 4,
+    "file_path": "Token.sol",
+    "id": "import:a2e94e572fe1823c82b046dd0a3030d9",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "import",
+    "language": "solidity",
+    "name": "./IERC20.sol",
+    "qualified_name": "./IERC20.sol",
+    "return_type": null,
+    "signature": "import \"./IERC20.sol\";",
+    "start_column": 0,
+    "start_line": 4,
+    "type_parameters": null,
+    "visibility": null
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 1,
+    "end_line": 6,
+    "file_path": "IERC20.sol",
+    "id": "interface:cc05f27c43c35cc4ab3d86bb6f06872c",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "interface",
+    "language": "solidity",
+    "name": "IERC20",
+    "qualified_name": "IERC20",
+    "return_type": null,
+    "signature": null,
+    "start_column": 0,
+    "start_line": 4,
+    "type_parameters": null,
+    "visibility": null
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 5,
+    "end_line": 48,
+    "file_path": "Token.sol",
+    "id": "method:01522a942d17de1001d5a8e65bbe316a",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "method",
+    "language": "solidity",
+    "name": "add",
+    "qualified_name": "Math::add",
+    "return_type": null,
+    "signature": "(uint256 a, uint256 b) internal pure returns (uint256)",
+    "start_column": 4,
+    "start_line": 46,
+    "type_parameters": null,
+    "visibility": "internal"
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 5,
+    "end_line": 34,
+    "file_path": "Token.sol",
+    "id": "method:069c78f8d4d5c513593c3c944014a0b0",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "method",
+    "language": "solidity",
+    "name": "fallback",
+    "qualified_name": "Token::fallback",
+    "return_type": null,
+    "signature": "() external",
+    "start_column": 4,
+    "start_line": 33,
+    "type_parameters": null,
+    "visibility": "public"
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 73,
+    "end_line": 5,
+    "file_path": "IERC20.sol",
+    "id": "method:14e6265384fe621344552d55e10f8466",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "method",
+    "language": "solidity",
+    "name": "transfer",
+    "qualified_name": "IERC20::transfer",
+    "return_type": null,
+    "signature": "(address to, uint256 value) external returns (bool)",
+    "start_column": 4,
+    "start_line": 5,
+    "type_parameters": null,
+    "visibility": "public"
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 5,
+    "end_line": 42,
+    "file_path": "Token.sol",
+    "id": "method:1c8a7b45450c9d4eed6e478286852ad3",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "method",
+    "language": "solidity",
+    "name": "transfer",
+    "qualified_name": "Token::transfer",
+    "return_type": null,
+    "signature": "(address to, uint256 value) public returns (bool)",
+    "start_column": 4,
+    "start_line": 39,
+    "type_parameters": null,
+    "visibility": "public"
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 5,
+    "end_line": 31,
+    "file_path": "Token.sol",
+    "id": "method:46d4bf9937e477f5bd270bb05b6696f0",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "method",
+    "language": "solidity",
+    "name": "constructor",
+    "qualified_name": "Token::constructor",
+    "return_type": null,
+    "signature": "()",
+    "start_column": 4,
+    "start_line": 29,
+    "type_parameters": null,
+    "visibility": null
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 5,
+    "end_line": 37,
+    "file_path": "Token.sol",
+    "id": "method:768b3877a930b3ee9c3b24466c601f38",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "method",
+    "language": "solidity",
+    "name": "receive",
+    "qualified_name": "Token::receive",
+    "return_type": null,
+    "signature": "() external payable",
+    "start_column": 4,
+    "start_line": 36,
+    "type_parameters": null,
+    "visibility": "public"
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 5,
+    "end_line": 27,
+    "file_path": "Token.sol",
+    "id": "method:d56cce424b1c30328b00f0b981df8233",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "method",
+    "language": "solidity",
+    "name": "onlyOwner",
+    "qualified_name": "Token::onlyOwner",
+    "return_type": null,
+    "signature": "()",
+    "start_column": 4,
+    "start_line": 25,
+    "type_parameters": null,
+    "visibility": null
+  },
+  {
+    "decorators": null,
+    "docstring": null,
+    "end_column": 5,
+    "end_line": 23,
+    "file_path": "Token.sol",
+    "id": "struct:6879c4fba147cd44c382552884de5563",
+    "is_abstract": 0,
+    "is_async": 0,
+    "is_exported": 0,
+    "is_static": 0,
+    "kind": "struct",
+    "language": "solidity",
+    "name": "Holder",
+    "qualified_name": "Token::Holder",
+    "return_type": null,
+    "signature": null,
+    "start_column": 4,
+    "start_line": 20,
+    "type_parameters": null,
+    "visibility": null
+  }
+]
diff --git a/reference/golden/solidity/refs.json b/reference/golden/solidity/refs.json
new file mode 100644
index 0000000..fe51488
--- /dev/null
+++ b/reference/golden/solidity/refs.json
@@ -0,0 +1 @@
+[]
diff --git a/reference/golden/solidity/schema.sql b/reference/golden/solidity/schema.sql
new file mode 100644
index 0000000..d36218f
--- /dev/null
+++ b/reference/golden/solidity/schema.sql
@@ -0,0 +1,117 @@
+CREATE TABLE schema_versions (
+version INTEGER PRIMARY KEY,
+applied_at INTEGER NOT NULL,
+description TEXT
+);
+CREATE TABLE nodes (
+id TEXT PRIMARY KEY,
+kind TEXT NOT NULL,
+name TEXT NOT NULL,
+qualified_name TEXT NOT NULL,
+file_path TEXT NOT NULL,
+language TEXT NOT NULL,
+start_line INTEGER NOT NULL,
+end_line INTEGER NOT NULL,
+start_column INTEGER NOT NULL,
+end_column INTEGER NOT NULL,
+docstring TEXT,
+signature TEXT,
+visibility TEXT,
+is_exported INTEGER DEFAULT 0,
+is_async INTEGER DEFAULT 0,
+is_static INTEGER DEFAULT 0,
+is_abstract INTEGER DEFAULT 0,
+decorators TEXT, -- JSON array
+type_parameters TEXT, -- JSON array
+return_type TEXT, -- normalized return/result type name (e.g. C++ method return, for receiver-type inference)
+updated_at INTEGER NOT NULL
+);
+CREATE TABLE edges (
+id INTEGER PRIMARY KEY AUTOINCREMENT,
+source TEXT NOT NULL,
+target TEXT NOT NULL,
+kind TEXT NOT NULL,
+metadata TEXT, -- JSON object
+line INTEGER,
+col INTEGER,
+provenance TEXT DEFAULT NULL,
+FOREIGN KEY (source) REFERENCES nodes(id) ON DELETE CASCADE,
+FOREIGN KEY (target) REFERENCES nodes(id) ON DELETE CASCADE
+);
+CREATE TABLE sqlite_sequence(name,seq);
+CREATE TABLE files (
+path TEXT PRIMARY KEY,
+content_hash TEXT NOT NULL,
+language TEXT NOT NULL,
+size INTEGER NOT NULL,
+modified_at INTEGER NOT NULL,
+indexed_at INTEGER NOT NULL,
+node_count INTEGER DEFAULT 0,
+errors TEXT -- JSON array
+);
+CREATE TABLE unresolved_refs (
+id INTEGER PRIMARY KEY AUTOINCREMENT,
+from_node_id TEXT NOT NULL,
+reference_name TEXT NOT NULL,
+reference_kind TEXT NOT NULL,
+line INTEGER NOT NULL,
+col INTEGER NOT NULL,
+candidates TEXT, -- JSON array
+file_path TEXT NOT NULL DEFAULT '',
+language TEXT NOT NULL DEFAULT 'unknown',
+reference_subkind TEXT,
+FOREIGN KEY (from_node_id) REFERENCES nodes(id) ON DELETE CASCADE
+);
+CREATE INDEX idx_nodes_kind ON nodes(kind);
+CREATE INDEX idx_nodes_name ON nodes(name);
+CREATE INDEX idx_nodes_qualified_name ON nodes(qualified_name);
+CREATE INDEX idx_nodes_file_path ON nodes(file_path);
+CREATE INDEX idx_nodes_language ON nodes(language);
+CREATE INDEX idx_nodes_file_line ON nodes(file_path, start_line);
+CREATE INDEX idx_nodes_lower_name ON nodes(lower(name));
+CREATE VIRTUAL TABLE nodes_fts USING fts5(
+id,
+name,
+qualified_name,
+docstring,
+signature,
+content='nodes',
+content_rowid='rowid'
+)
+/* nodes_fts(id,name,qualified_name,docstring,signature) */;
+CREATE TABLE 'nodes_fts_data'(id INTEGER PRIMARY KEY, block BLOB);
+CREATE TABLE 'nodes_fts_idx'(segid, term, pgno, PRIMARY KEY(segid, term)) WITHOUT ROWID;
+CREATE TABLE 'nodes_fts_docsize'(id INTEGER PRIMARY KEY, sz BLOB);
+CREATE TABLE 'nodes_fts_config'(k PRIMARY KEY, v) WITHOUT ROWID;
+CREATE TRIGGER nodes_ai AFTER INSERT ON nodes BEGIN
+INSERT INTO nodes_fts(rowid, id, name, qualified_name, docstring, signature)
+VALUES (NEW.rowid, NEW.id, NEW.name, NEW.qualified_name, NEW.docstring, NEW.signature);
+END;
+CREATE TRIGGER nodes_ad AFTER DELETE ON nodes BEGIN
+INSERT INTO nodes_fts(nodes_fts, rowid, id, name, qualified_name, docstring, signature)
+VALUES ('delete', OLD.rowid, OLD.id, OLD.name, OLD.qualified_name, OLD.docstring, OLD.signature);
+END;
+CREATE TRIGGER nodes_au AFTER UPDATE ON nodes BEGIN
+INSERT INTO nodes_fts(nodes_fts, rowid, id, name, qualified_name, docstring, signature)
+VALUES ('delete', OLD.rowid, OLD.id, OLD.name, OLD.qualified_name, OLD.docstring, OLD.signature);
+INSERT INTO nodes_fts(rowid, id, name, qualified_name, docstring, signature)
+VALUES (NEW.rowid, NEW.id, NEW.name, NEW.qualified_name, NEW.docstring, NEW.signature);
+END;
+CREATE INDEX idx_edges_kind ON edges(kind);
+CREATE INDEX idx_edges_source_kind ON edges(source, kind);
+CREATE INDEX idx_edges_target_kind ON edges(target, kind);
+CREATE UNIQUE INDEX idx_edges_identity
+ON edges(source, target, kind, IFNULL(line, -1), IFNULL(col, -1));
+CREATE INDEX idx_files_language ON files(language);
+CREATE INDEX idx_files_modified_at ON files(modified_at);
+CREATE INDEX idx_unresolved_from_node ON unresolved_refs(from_node_id);
+CREATE INDEX idx_unresolved_name ON unresolved_refs(reference_name);
+CREATE INDEX idx_unresolved_file_path ON unresolved_refs(file_path);
+CREATE INDEX idx_unresolved_from_name ON unresolved_refs(from_node_id, reference_name);
+CREATE INDEX idx_edges_provenance ON edges(provenance);
+CREATE TABLE project_metadata (
+key TEXT PRIMARY KEY,
+value TEXT NOT NULL,
+updated_at INTEGER NOT NULL
+);
+CREATE TABLE sqlite_stat1(tbl,idx,stat);
