Now I have all the context needed. Let me generate the section content.

# Section 6: Integration Tests and Sprint 0 Fixes

## Overview

This final section adds integration tests that exercise the full parsing pipeline end-to-end and updates Sprint 0 test expectations to accommodate the `parse_tscn` API change from content-based to path-based. After this section is complete, the entire test suite (Sprint 0 + Sprint 1) must pass with zero failures.

**Dependencies:** Sections 03 (state machine parser), 04 (tree queries), and 05 (fixtures and unit tests) must be fully implemented before this section. All fixture files must exist in `tests/fixtures/`.

## Background

The parser system built in Sections 1-5 provides:
- `parse_tscn(path: str) -> TscnScene` -- reads a `.tscn` file from disk and returns a fully parsed scene
- `TscnScene` with query methods: `find_node()`, `get_nodes_by_group()`, `get_nodes_by_type()`, `get_all_scripts()`, `get_all_instances()`
- Tree reconstruction (parent-child hierarchy built from flat node list)
- Transform3D decomposition into position/rotation/scale tuples
- Value parsing for all Godot types

The integration tests validate that these components work together correctly across all fixture files. The Sprint 0 fix ensures backward compatibility of the test suite after the API signature change.

## File Inventory

| File | Action |
|------|--------|
| `tests/test_parsers/test_tscn_integration.py` | **CREATE** -- 8 integration tests |
| `tests/test_server.py` | **MODIFY** -- update `test_parser_stubs_raise` |

## Tests First

All tests go in a new file. Write these tests before any other changes in this section.

### File: `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_parsers/test_tscn_integration.py`

```python
"""Integration tests for the TSCN parser pipeline.

Tests the full roundtrip: file on disk -> parse_tscn() -> TscnScene with
populated tree, query methods, and transform decomposition.
"""

from pathlib import Path

import pytest

from godotiq.parsers.tscn_parser import parse_tscn, TscnScene, TscnNode

FIXTURES = Path(__file__).resolve().parent.parent / "fixtures"


class TestParseAllFixturesWithoutExceptions:
    """Parse every fixture file and verify no exceptions are raised."""

    @pytest.mark.parametrize("filename", [
        "worker.tscn",
        "fdm_printer.tscn",
        "furniture_slot_placeholder.tscn",
        "main.tscn",
    ])
    def test_parse_fixture_no_exceptions(self, filename: str) -> None:
        """Each fixture file parses successfully and returns a TscnScene."""
        path = FIXTURES / filename
        scene = parse_tscn(str(path))
        assert isinstance(scene, TscnScene)
        assert scene.root is not None
        assert len(scene.nodes) > 0

    @pytest.mark.parametrize("filename", [
        "worker.tscn",
        "fdm_printer.tscn",
        "furniture_slot_placeholder.tscn",
        "main.tscn",
    ])
    def test_all_nodes_have_non_empty_name(self, filename: str) -> None:
        """Every parsed node must have a non-empty name string."""
        scene = parse_tscn(str(FIXTURES / filename))
        for node in scene.nodes:
            assert node.name, f"Node with empty name found in {filename}"


class TestTransformIntegrity:
    """Nodes with transforms must have position, rotation, and scale set."""

    def test_worker_transform_nodes_have_all_components(self) -> None:
        """worker.tscn: nodes with transform have pos/rot/scale."""
        scene = parse_tscn(str(FIXTURES / "worker.tscn"))
        for node in scene.nodes:
            if node.position is not None:
                assert node.rotation is not None
                assert node.scale is not None
                assert len(node.position) == 3
                assert len(node.rotation) == 3
                assert len(node.scale) == 3

    def test_main_transform_nodes_have_all_components(self) -> None:
        """main.tscn: all nodes with transforms are complete 3-tuples."""
        scene = parse_tscn(str(FIXTURES / "main.tscn"))
        for node in scene.nodes:
            if node.position is not None:
                assert node.rotation is not None, (
                    f"Node '{node.name}' has position but no rotation"
                )
                assert node.scale is not None, (
                    f"Node '{node.name}' has position but no scale"
                )


class TestQueryMethodsIntegration:
    """Test that query methods return correct, consistent results."""

    def test_find_node_multi_level_path_main(self) -> None:
        """find_node with a multi-segment path works on main.tscn."""
        scene = parse_tscn(str(FIXTURES / "main.tscn"))
        # This path is known to exist from the plan (Section 4 tests)
        node = scene.find_node("Building/LockedZones/PostProcessingZone")
        assert node is not None
        assert node.name == "PostProcessingZone"

    def test_get_all_scripts_returns_valid_res_paths(self) -> None:
        """get_all_scripts() returns only res:// prefixed paths."""
        scene = parse_tscn(str(FIXTURES / "main.tscn"))
        scripts = scene.get_all_scripts()
        assert len(scripts) > 0
        for path in scripts:
            assert path.startswith("res://"), (
                f"Script path '{path}' does not start with res://"
            )

    def test_get_all_instances_returns_valid_res_paths(self) -> None:
        """get_all_instances() returns only res:// prefixed paths."""
        scene = parse_tscn(str(FIXTURES / "main.tscn"))
        instances = scene.get_all_instances()
        assert len(instances) > 0
        for path in instances:
            assert path.startswith("res://"), (
                f"Instance path '{path}' does not start with res://"
            )

    def test_get_nodes_by_group_returns_nodes_with_that_group(self) -> None:
        """get_nodes_by_group results actually contain the queried group."""
        scene = parse_tscn(str(FIXTURES / "fdm_printer.tscn"))
        nodes = scene.get_nodes_by_group("interactable")
        assert len(nodes) > 0
        for node in nodes:
            assert "interactable" in node.groups

    def test_get_nodes_by_type_returns_nodes_with_that_type(self) -> None:
        """get_nodes_by_type results actually match the queried type."""
        scene = parse_tscn(str(FIXTURES / "worker.tscn"))
        nodes = scene.get_nodes_by_type("CollisionShape3D")
        assert len(nodes) > 0
        for node in nodes:
            assert node.type == "CollisionShape3D"
```

The tests are organized into four classes:

1. **TestParseAllFixturesWithoutExceptions** -- Parametrized across all four fixture files. Confirms parsing succeeds and every node has a non-empty name. This is the most basic smoke test that the full pipeline works.

2. **TestTransformIntegrity** -- Validates that Transform3D decomposition produces complete 3-tuples for position, rotation, and scale. If any one component is present, all three must be present and have length 3.

3. **TestQueryMethodsIntegration** -- Exercises every query method on `TscnScene`:
   - `find_node()` with a multi-segment path on `main.tscn`
   - `get_all_scripts()` returns `res://` paths
   - `get_all_instances()` returns `res://` paths
   - `get_nodes_by_group()` returns nodes that genuinely belong to the queried group
   - `get_nodes_by_type()` returns nodes that genuinely have the queried type

### Test Count

The file contains 8 test functions (the two parametrized tests each produce 4 sub-tests for a total of 12 actual test runs, but 8 logical test definitions).

## Sprint 0 Test Update

### File: `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_server.py`

The `TestParserStubs` class must be updated because `parse_tscn` no longer raises `NotImplementedError`. It now accepts a file path and raises `FileNotFoundError` for nonexistent paths.

**Current code (lines 39-48):**

```python
class TestParserStubs:
    """AC-4: All parser placeholders raise NotImplementedError."""

    def test_parser_stubs_raise(self) -> None:
        with pytest.raises(NotImplementedError):
            parse_tscn("")
        with pytest.raises(NotImplementedError):
            parse_gd("")
        with pytest.raises(NotImplementedError):
            parse_tres("")
```

**Updated code:**

```python
class TestParserStubs:
    """AC-4: Parser placeholders and implemented parsers behave correctly."""

    def test_parse_tscn_raises_file_not_found_for_bad_path(self) -> None:
        """parse_tscn is implemented and raises FileNotFoundError for nonexistent path."""
        with pytest.raises(FileNotFoundError):
            parse_tscn("/nonexistent/path/scene.tscn")

    def test_parse_gd_stub_raises(self) -> None:
        """parse_gd is still a Sprint 0 placeholder."""
        with pytest.raises(NotImplementedError):
            parse_gd("")

    def test_parse_tres_stub_raises(self) -> None:
        """parse_tres is still a Sprint 0 placeholder."""
        with pytest.raises(NotImplementedError):
            parse_tres("")
```

**What changed:**
- The single `test_parser_stubs_raise` method is split into three separate test methods for clarity.
- The `parse_tscn` assertion changes from `NotImplementedError` to `FileNotFoundError` with a nonexistent path string. This confirms the new path-based API is active.
- The `parse_gd` and `parse_tres` assertions remain unchanged -- they still expect `NotImplementedError`.
- The class docstring is updated to reflect that not all parsers are stubs anymore.

**Impact on test count:** The original test file had 1 test method for stubs; the new version has 3. The total test count in `test_server.py` increases by 2 (from 4 to 6 test methods).

## Implementation Details

### Step 1: Create the integration test file

Create `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_parsers/test_tscn_integration.py` with the test code shown above. The file imports `parse_tscn`, `TscnScene`, and `TscnNode` from `godotiq.parsers.tscn_parser`. It uses `pathlib.Path` to locate fixture files relative to the test file itself.

The `FIXTURES` constant resolves to `tests/fixtures/` via:
```python
FIXTURES = Path(__file__).resolve().parent.parent / "fixtures"
```

This works because the test file is at `tests/test_parsers/test_tscn_integration.py`, so `.parent.parent` is `tests/`.

### Step 2: Update the Sprint 0 test file

Modify `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_server.py` as described above. Replace the `TestParserStubs` class with the three-method version. Keep all other classes (`TestServerInstance`, `TestPingTool`, `TestConfig`) unchanged.

The imports at the top of `test_server.py` remain the same -- `parse_tscn`, `parse_gd`, and `parse_tres` are all still imported.

### Step 3: Verify the test_scaffolding_int.py compatibility

The file `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_scaffolding_int.py` imports `parse_tscn` at line 89:
```python
from godotiq.parsers.tscn_parser import TscnNode, TscnScene, parse_tscn
```

This import continues to work because `parse_tscn` is still exported from the same module with the same name. The scaffolding test only checks that the symbol is callable (`assert callable(parse_tscn)`), which remains true. No changes needed to this file.

### Step 4: Run the full test suite

After creating the integration test file and updating `test_server.py`, run the complete test suite:

```
pytest tests/ -v --ignore tests/test_scaffolding_e2e.py
```

The E2E scaffolding test is excluded because it re-runs pytest in a subprocess and adds significant time. All other tests should pass.

**Expected test counts:**
- `tests/test_server.py` -- 6 tests (2 server instance/ping + 3 parser stubs + 1 config... actually: `TestServerInstance` has 1, `TestPingTool` has 2, `TestParserStubs` has 3, `TestConfig` has 2 = 8 total)
- `tests/test_scaffolding_int.py` -- 3 tests
- `tests/test_parsers/test_value_parser.py` -- tests from Section 1/5
- `tests/test_parsers/test_tscn_parser.py` -- 23 tests from Section 5
- `tests/test_parsers/test_tscn_integration.py` -- 8 test functions (12 parametrized runs)

All tests must pass with 0 failures.

### Step 5: Verify performance

Parse `main.tscn` (4711 lines, 876 nodes) and confirm it completes in under 200ms. This can be checked with a simple timing assertion or by running pytest with `--durations=0` and inspecting the integration test timing for `main.tscn`. If it exceeds 200ms, the parser may need optimization (likely in multiline value accumulation or regex compilation -- ensure regex patterns are pre-compiled at module level, not per-call).

A lightweight performance check can be added as an additional test if desired:

```python
import time

def test_main_tscn_performance(self) -> None:
    """main.tscn (4711 lines) parses in under 200ms."""
    path = str(FIXTURES / "main.tscn")
    start = time.perf_counter()
    scene = parse_tscn(path)
    elapsed_ms = (time.perf_counter() - start) * 1000
    assert elapsed_ms < 200, f"Parsing took {elapsed_ms:.1f}ms (limit: 200ms)"
    assert len(scene.nodes) == 876
```

This test is optional but recommended. If included, place it in the `TestParseAllFixturesWithoutExceptions` class or as a standalone class.

## Checklist

- [ ] Create `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_parsers/test_tscn_integration.py` with 8 integration tests
- [ ] Update `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_server.py` -- replace `TestParserStubs` class with three separate test methods
- [ ] Verify `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_scaffolding_int.py` still passes without changes
- [ ] Run `pytest tests/ -v --ignore tests/test_scaffolding_e2e.py` and confirm 0 failures
- [ ] Verify `main.tscn` parses in under 200ms (check test durations or add explicit timing test)