Now I have all the information I need. Here is the section content:

# Section 05: Integration Tests

## Overview

This section adds integration tests to `tests/test_parsers/test_gd_parser.py`. These tests parse real `.gd` fixture files (not inline strings) and validate structural correctness of the parsed output. They complement the unit tests from section-04 which use `_parse_gd_content()` with inline strings.

**File to modify:** `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_parsers/test_gd_parser.py`

**Dependencies:** Sections 01 through 04 must be complete. The full parser (`parse_gd`, `_parse_gd_content`, all dataclasses) and unit tests must exist before adding integration tests.

**Constraint:** All 127 existing Sprint 0/1 tests must continue to pass. Do NOT modify any existing test files.

## Important Context: Existing Sprint 0 Tests

Two existing test files reference `parse_gd`:

1. **`/Users/salvatorefarruggio/Desktop/godotiq/tests/test_server.py`** -- `test_parse_gd_stub_raises` expects `parse_gd("")` to raise `NotImplementedError`. After the parser is implemented, this test will fail because the signature changes from `parse_gd(content: str)` to `parse_gd(path: str, known_autoloads=None)`. Passing `""` as a path will raise `FileNotFoundError` (not `NotImplementedError`). This test must be updated to expect `FileNotFoundError` instead, or removed. The plan states the stub signature is changing and the existing Sprint 0 tests "reference `parse_gd` but only test that it exists and raises `FileNotFoundError` for bad paths -- they will work with the new path-based signature." So the existing test in `test_server.py` at line 47-49 needs to be updated to expect `FileNotFoundError` rather than `NotImplementedError`. This is handled implicitly by the implementation sections (section-02 changes `parse_gd`), but the integration test section should verify it works.

2. **`/Users/salvatorefarruggio/Desktop/godotiq/tests/test_scaffolding_int.py`** -- imports `parse_gd` and checks `callable(parse_gd)`. This will continue to work with the new signature.

## Fixture Files

The integration tests use these real `.gd` files already present in the repository:

| Fixture | Path | Key Features |
|---------|------|--------------|
| economy_manager.gd | `/Users/salvatorefarruggio/Desktop/godotiq/tests/fixtures/economy_manager.gd` | class_name, extends, 3 signals, 8 functions, 5 class vars, multiple .emit() calls |
| printer_manager.gd | `/Users/salvatorefarruggio/Desktop/godotiq/tests/fixtures/printer_manager.gd` | Printer.State custom types in signals, is_instance_valid usage, signal connections in register_printer, get_node_or_null and has_node patterns |
| game_manager.gd | `/Users/salvatorefarruggio/Desktop/godotiq/tests/fixtures/game_manager.gd` | enum GameState, autoload refs (EconomyManager, ResearchManager), has_node/get_node patterns, multiline var session_stats |
| progression_manager.gd | `/Users/salvatorefarruggio/Desktop/godotiq/tests/fixtures/progression_manager.gd` | multiline const LEVEL_XP (array), multiline const UNLOCK_TABLE (dict), lambda in connect, 4 signals |
| printer.gd | `/Users/salvatorefarruggio/Desktop/godotiq/tests/fixtures/sample_project/scripts/entities/printer.gd` | Minimal: just `extends Node3D` |
| worker.gd | `/Users/salvatorefarruggio/Desktop/godotiq/tests/fixtures/sample_project/scripts/entities/worker.gd` | Minimal: just `extends CharacterBody3D` |

## Tests to Write

All tests go in the `TestIntegration` class appended to the existing file `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_parsers/test_gd_parser.py`. Follow the same patterns used in `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_parsers/test_tscn_integration.py` -- use a module-level `FIXTURES` path constant and `parse_gd(str(path))`.

### Setup Pattern

```python
from pathlib import Path
from godotiq.parsers.gd_parser import parse_gd, GdScript

FIXTURES = Path(__file__).resolve().parent.parent / "fixtures"
SAMPLE_FIXTURES = FIXTURES / "sample_project" / "scripts" / "entities"
```

Note: since section-04 already creates this file, the `FIXTURES` constant and imports may already exist. The integration class should be appended below the existing unit test classes.

### TestIntegration Class

This class uses the public `parse_gd(path)` function (not `_parse_gd_content`) and validates against real fixture file contents.

#### Test: Parse all fixtures without exceptions (parametrized)

Parametrize over all 6 fixture files. Each call to `parse_gd(str(path))` must return a `GdScript` instance without raising. This is the smoke test.

```python
@pytest.mark.parametrize("fixture_path", [
    FIXTURES / "economy_manager.gd",
    FIXTURES / "printer_manager.gd",
    FIXTURES / "game_manager.gd",
    FIXTURES / "progression_manager.gd",
    SAMPLE_FIXTURES / "printer.gd",
    SAMPLE_FIXTURES / "worker.gd",
])
def test_parse_fixture_no_exceptions(self, fixture_path: Path) -> None:
    """Every fixture file parses without raising."""
```

Assert the result is a `GdScript` instance.

#### Test: economy_manager.gd structural assertions

Parse `/Users/salvatorefarruggio/Desktop/godotiq/tests/fixtures/economy_manager.gd` and assert:

- `class_name == "EconomyManagerClass"`
- `extends == "Node"`
- 3 signals: `cash_changed`, `transaction_recorded`, `insufficient_funds`
- `cash_changed` has typed args: `[("new_amount", "float"), ("delta", "float")]`
- 8 functions: `_ready`, `add_cash`, `spend_cash`, `can_afford`, `get_profit`, `_record_transaction`, `serialize`, `deserialize`
- 5 class-level variables: `cash`, `total_earned`, `total_spent`, `transaction_history`, `max_history`
- `cash` variable has `type_hint == "float"` and `default_value == "100.0"`
- Multiple `.emit()` calls exist (the signal_emissions list is non-empty)
- `cash_changed` appears in signal_emissions with `arg_count == 2`

```python
def test_economy_manager(self) -> None:
    """economy_manager.gd: class_name, extends, signals, functions, variables, emissions."""
```

#### Test: printer_manager.gd structural assertions

Parse `/Users/salvatorefarruggio/Desktop/godotiq/tests/fixtures/printer_manager.gd` and assert:

- `class_name == "PrinterManagerClass"`
- `extends == "Node"`
- 5 signals including `any_state_changed` which has `Printer.State` custom type in args
- Specifically, `any_state_changed` has args containing tuples where the type is `"Printer.State"`
- `is_instance_valid_lines` is non-empty (the file has many `is_instance_valid()` calls -- at least 8)
- Signal connections exist: at least 4 connections in the file (the `register_printer` function connects `print_started`, `print_completed`, `print_failed`, `state_changed`)
- Verify a connection has `signal_source` containing `"print_started"` and `target` of `"_on_print_started"`
- `get_node_or_null` autoload refs detected: the `deserialize` function calls `get_tree().root.get_node_or_null("Main/Systems/ProductDatabase")` and `get_tree().root.get_node_or_null("Main/Systems/MaterialDatabase")`
- `has_node("/root/ResearchManager")` pattern detected in autoload_refs
- Multiple `.emit()` calls exist

```python
def test_printer_manager(self) -> None:
    """printer_manager.gd: Printer.State types, is_instance_valid, connections, autoload patterns."""
```

Note: For autoload direct-pattern detection, pass `known_autoloads=["ResearchManager", "SlicerManager"]` since the file references `ResearchManager.check_eureka(...)` and `ResearchManager.record_daily_print(...)` and `SlicerManager`.

#### Test: game_manager.gd structural assertions

Parse `/Users/salvatorefarruggio/Desktop/godotiq/tests/fixtures/game_manager.gd` with `known_autoloads=["EconomyManager", "ResearchManager", "ProgressionManager"]` and assert:

- `class_name == "GameManagerClass"`
- `extends == "Node"`
- 1 enum named `"GameState"` with values including `"PLAYING"`, `"PAUSED"`, `"DAILY_SUMMARY"` (all with `None` as value since no explicit integer values)
- 3 signals: `game_state_changed`, `new_day_started`, `game_hour_changed`
- The `session_stats` variable is captured as a class-level variable. It is a multiline `Dictionary` initialized with `{...}` spanning lines 15-24. The parser should capture it via IN_MULTILINE_VALUE. Assert that a variable named `session_stats` exists with `type_hint == "Dictionary"`
- Autoload refs for `EconomyManager` detected with `pattern == "direct"` (line 55: `EconomyManager.spend_cash(...)`)
- Autoload refs for `ResearchManager` detected with `pattern == "direct"` (lines 58-59: `ResearchManager.has_method(...)`, `ResearchManager.update_freshness(...)`)
- `has_node("/root/ProgressionManager")` detected as autoload ref with `pattern == "has_node"` (line 116)
- `get_node("/root/ProgressionManager")` detected as autoload ref with `pattern == "get_node"` (line 117)
- `get_node_or_null` pattern detected for `"Main/Systems/PrinterSlotManager"` (line 75)
- `is_instance_valid_lines` is non-empty (line 76: `is_instance_valid(slot_mgr)`)

```python
def test_game_manager(self) -> None:
    """game_manager.gd: enum, autoload refs, has_node/get_node, multiline var."""
```

#### Test: progression_manager.gd structural assertions

Parse `/Users/salvatorefarruggio/Desktop/godotiq/tests/fixtures/progression_manager.gd` with `known_autoloads=["GameManager"]` and assert:

- `class_name == "ProgressionManagerClass"`
- `extends == "Node"`
- 4 signals: `xp_gained`, `level_up`, `product_unlocked`, `feature_unlocked`
- `LEVEL_XP` exists as a const variable (`is_const == True`) with `type_hint == "Array[int]"`. Its `default_value` should be non-empty and contain the multiline array content (accumulated from lines 12-23)
- `UNLOCK_TABLE` exists as a const variable (`is_const == True`) with `type_hint == "Dictionary"`. Its `default_value` should be non-empty (accumulated from lines 27-38, the multiline dict)
- The lambda connect on line 256: `level_up.connect(func(_l, _u): level_up_fired[0] = true)` should be detected as a `GdSignalConnection` with `signal_source` containing `"level_up"` and `target` starting with `"func"`
- `is_instance_valid_lines` is non-empty (lines 96, 118 reference `is_instance_valid()`)
- `get_node_or_null` pattern detected for `"Main/Systems/ProductDatabase"` (line 95)
- Direct autoload ref for `GameManager` detected (line 214: `GameManager.game_time`)

```python
def test_progression_manager(self) -> None:
    """progression_manager.gd: multiline const, lambda connect, 4 signals."""
```

#### Test: Minimal fixtures (printer.gd, worker.gd)

Parse the minimal fixtures and assert they parse cleanly with only `extends` set:

- `/Users/salvatorefarruggio/Desktop/godotiq/tests/fixtures/sample_project/scripts/entities/printer.gd`: `extends == "Node3D"`, `class_name == ""`, empty signals/functions/variables/enums
- `/Users/salvatorefarruggio/Desktop/godotiq/tests/fixtures/sample_project/scripts/entities/worker.gd`: `extends == "CharacterBody3D"`, everything else empty

```python
def test_minimal_printer_fixture(self) -> None:
    """Minimal printer.gd: only extends Node3D."""

def test_minimal_worker_fixture(self) -> None:
    """Minimal worker.gd: only extends CharacterBody3D."""
```

#### Test: Missing file raises FileNotFoundError

Verify that calling `parse_gd` with a nonexistent path raises `FileNotFoundError`, matching `parse_tscn` behavior.

```python
def test_missing_file_raises(self) -> None:
    """parse_gd with nonexistent path raises FileNotFoundError."""
```

### Specific Count Verification (from fixture analysis)

These counts were derived by manually analyzing the fixture files. They serve as regression anchors.

**economy_manager.gd counts:**

| Feature | Expected Count |
|---------|---------------|
| Signals | 3 |
| Functions | 8 (`_ready`, `add_cash`, `spend_cash`, `can_afford`, `get_profit`, `_record_transaction`, `serialize`, `deserialize`) |
| Class variables | 5 (`cash`, `total_earned`, `total_spent`, `transaction_history`, `max_history`) |
| Signal emissions | At least 5 (`cash_changed.emit` x3, `insufficient_funds.emit` x1, `transaction_recorded.emit` x1) |
| Enums | 0 |
| Inner classes | 0 |

**printer_manager.gd counts:**

| Feature | Expected Count |
|---------|---------------|
| Signals | 5 (`printer_registered`, `any_print_started`, `any_print_completed`, `any_print_failed`, `any_state_changed`) |
| Functions | At least 16 (including `_ready`, `_verify`, `register_printer`, `get_printer`, `get_idle_printers`, `get_all_printers`, `get_max_printer_tier`, `get_printer_data`, `_state_to_string`, `reserve_printer_for_research`, `release_printer`, `has_idle_printer`, `get_total_production_stats`, `_sum_production_stats`, `start_print_on`, `_on_print_started`, `_on_print_completed`, `_on_print_failed`, `_on_state_changed`, `serialize`, `deserialize`) |
| Class variables | 1 (`printers`) |
| Signal connections | 4 (in `register_printer`: `print_started`, `print_completed`, `print_failed`, `state_changed`) |
| is_instance_valid lines | At least 8 |

**game_manager.gd counts:**

| Feature | Expected Count |
|---------|---------------|
| Signals | 3 |
| Enums | 1 (`GameState`) |
| Functions | At least 10 |
| Class variables | At least 7 (`current_state`, `game_speed`, `game_day`, `game_hour`, `game_time`, `is_paused`, `is_first_launch`, `session_stats`, `daily_costs_breakdown`) |

**progression_manager.gd counts:**

| Feature | Expected Count |
|---------|---------------|
| Signals | 4 |
| Constants (is_const=True) | At least 2 (`LEVEL_XP`, `UNLOCK_TABLE`) |
| Functions | At least 14 |

## Implementation Notes

1. **Use `parse_gd(str(path))` not `_parse_gd_content()`** -- integration tests exercise the full public API including file reading.

2. **Pass `known_autoloads` where needed** -- autoload direct-pattern detection requires the caller to supply known names. Tests for `game_manager.gd` and `progression_manager.gd` should pass their known autoloads. Tests for `printer_manager.gd` should pass `["ResearchManager", "SlicerManager"]`.

3. **Use `>=` for count assertions where the plan says "at least"** -- some features like `is_instance_valid` may appear more times than initially counted. Use `>=` to avoid brittle tests if the fixture files have more occurrences than expected.

4. **Helper for finding items by name** -- use list comprehensions like `[s for s in result.signals if s.name == "cash_changed"]` to find specific items for detailed assertions.

5. **Follow existing project test conventions** -- class-based test groups, `test_<feature>_<scenario>()` naming, type hints on test methods, docstrings on each test.

6. **Existing test for `parse_gd` stub** -- The test in `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_server.py` at line 47-49 currently expects `NotImplementedError` from `parse_gd("")`. After implementation, `parse_gd("")` will raise `FileNotFoundError` since `""` is not a valid file path. That test must be updated (in a prior section or as part of the implementation) to expect `FileNotFoundError`. This section's `test_missing_file_raises` provides the correct behavior validation.

## Actual Implementation Notes

### Deviations from Plan
- **Lambda connect test:** The plan expected `target.startswith("func")` for progression_manager.gd, but the actual fixture uses `level_up.connect(_on_lvl)` (a regular function reference), not an inline lambda. Tests assert the connection exists with correct signal_source.
- **test_missing_file_raises:** Not duplicated in TestIntegration since it already exists in TestClassDeclarations.
- **test_all_sprint_tests_still_pass:** Removed during code review as a no-op (pytest run itself verifies this).

### Test Results
- 12 integration tests in TestIntegration class (6 parametrized smoke + 4 structural + 2 minimal)
- 218 total tests pass (91 gd_parser + 127 existing Sprint 0/1/1BC)
- All fixtures parse successfully with correct structural assertions