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

# Section 5: Test Fixtures and Unit Tests

## Overview

This section creates the `furniture_slot_placeholder.tscn` test fixture file and implements all unit tests for the TSCN parser and value parser. It depends on sections 01 through 04 being fully implemented (value parser, dataclasses, state machine parser, and tree queries).

## Dependencies

- **Section 01** (Value Parser): `src/godotiq/parsers/value_parser.py` must exist with `parse_value()` and `decompose_transform3d()`
- **Section 02** (Dataclasses): `src/godotiq/parsers/tscn_parser.py` must contain `SceneHeader`, `ExtResource`, `SubResource`, `Connection`, extended `TscnNode`, and extended `TscnScene` dataclasses
- **Section 03** (State Machine): `parse_tscn(path: str) -> TscnScene` must be fully operational, reading a `.tscn` file from disk and returning a populated `TscnScene`
- **Section 04** (Tree Queries): `TscnScene` must have `find_node()`, `get_nodes_by_group()`, `get_nodes_by_type()`, `get_all_scripts()`, `get_all_instances()` methods

## Existing Fixtures

These files already exist in `tests/fixtures/`:

- `worker.tscn` -- 19 lines, 4 nodes. Simple hierarchy with script, SubResource ref, transforms with translation.
- `fdm_printer.tscn` -- 29 lines, 6 nodes. Multiple ext_resources, instances, groups, uniform scale transform.
- `main.tscn` -- 4711 lines, 876 nodes. Stress test: 68 ext_resources, 142 sub_resources, deep nesting, metadata, scientific notation, special names, format=4.
- `filament_spool_item_new.tscn` -- 5 lines, 2 nodes. Minimal scene.

## Part 1: Create Fixture File

### File: `/Users/salvatorefarruggio/Desktop/godotiq/tests/fixtures/furniture_slot_placeholder.tscn`

Create a new `.tscn` fixture file. It must be a valid Godot 4.x scene file with exactly 37 lines and 6 nodes. The fixture must exercise the following parser features:

- 3 `sub_resource` blocks with different types: `StandardMaterial3D`, `BoxMesh`, `BoxShape3D`
- Property types: `Color` (albedo_color), `Vector3` (size), `int` (billboard, shading_mode), `float` (transparency)
- `material_override = SubResource(...)` reference on a node
- `mesh = SubResource(...)` reference on a node

The fixture represents a furniture placement slot placeholder -- a semi-transparent box marker used in a 3D game editor. The structure:

```
[gd_scene format=3 uid="uid://placeholder_furniture_slot"]

[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_placeholder"]
transparency = 1
shading_mode = 0
albedo_color = Color(0.2, 0.8, 0.3, 0.4)
billboard = 0

[sub_resource type="BoxMesh" id="BoxMesh_placeholder"]
size = Vector3(1, 0.5, 1)

[sub_resource type="BoxShape3D" id="BoxShape3D_placeholder"]
size = Vector3(1, 0.5, 1)

[node name="FurnitureSlotPlaceholder" type="Node3D"]

[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
material_override = SubResource("StandardMaterial3D_placeholder")
mesh = SubResource("BoxMesh_placeholder")

[node name="StaticBody3D" type="StaticBody3D" parent="."]
collision_layer = 4
collision_mask = 0

[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D"]
shape = SubResource("BoxShape3D_placeholder")

[node name="SlotMarker" type="Marker3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.25, 0)

[node name="Label3D" type="Label3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.6, 0)
text = "Slot"
font_size = 32
```

Verify the file has exactly 37 lines (including blank separator lines) and exactly 6 nodes. Adjust blank lines as needed to hit 37 lines total.

## Part 2: Value Parser Unit Tests

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

This file tests `parse_value()` and `decompose_transform3d()` from `src/godotiq/parsers/value_parser.py`. All tests import from `godotiq.parsers.value_parser`.

```python
"""Unit tests for the value parser module."""

import math
import pytest
from godotiq.parsers.value_parser import parse_value, decompose_transform3d


class TestScalarParsing:
    """Tests for bool, int, float, null, and string parsing."""

    def test_parse_true(self):
        """parse_value("true") returns Python True."""

    def test_parse_false(self):
        """parse_value("false") returns Python False."""

    def test_parse_null(self):
        """parse_value("null") returns Python None."""

    def test_parse_int(self):
        """parse_value("42") returns int 42."""

    def test_parse_float(self):
        """parse_value("3.14") returns float 3.14."""

    def test_parse_scientific_notation(self):
        """parse_value("-3.059797e-08") returns a float near zero."""

    def test_parse_string(self):
        """parse_value('"hello world"') returns "hello world" (quotes stripped)."""


class TestVectorMathTypes:
    """Tests for Vector2, Vector3, Color, Rect2, AABB, Quaternion."""

    def test_parse_vector2(self):
        """parse_value("Vector2(1.5, 2.0)") returns (1.5, 2.0)."""

    def test_parse_vector3(self):
        """parse_value("Vector3(1, 2, 3)") returns tuple of 3 floats."""

    def test_parse_vector3i(self):
        """parse_value("Vector3i(1, 2, 3)") returns (1, 2, 3) as ints."""

    def test_parse_color(self):
        """parse_value("Color(0.5, 0.3, 0.1, 1.0)") returns tuple of 4 floats."""

    def test_parse_rect2(self):
        """parse_value("Rect2(0, 0, 100, 50)") returns tuple of 4 floats."""

    def test_parse_aabb(self):
        """parse_value("AABB(-1, -1, -1, 2, 2, 2)") returns tuple of 6 floats."""

    def test_parse_quaternion(self):
        """parse_value("Quaternion(0, 0, 0, 1)") returns tuple of 4 floats."""


class TestReferenceTypes:
    """Tests for ExtResource, SubResource, NodePath, StringName."""

    def test_parse_ext_resource(self):
        """parse_value('ExtResource("1_abc")') returns ref with id "1_abc"."""

    def test_parse_sub_resource(self):
        """parse_value('SubResource("BoxShape3D_1ufgv")') returns ref with correct id."""

    def test_parse_node_path(self):
        """parse_value('NodePath("Path/To/Node")') returns string "Path/To/Node"."""

    def test_parse_string_name(self):
        """parse_value('StringName(&"signal_name")') returns string "signal_name"."""


class TestPackedArrays:
    """Tests for PackedByteArray, PackedFloat32Array stored as raw strings."""

    def test_packed_byte_array(self):
        """parse_value("PackedByteArray(...)") stores as raw string."""

    def test_packed_float32_array(self):
        """parse_value("PackedFloat32Array(1, 2, 3)") stores as raw string."""


class TestArraysAndDictionaries:
    """Tests for array and dictionary parsing with recursive nesting."""

    def test_parse_string_array(self):
        """parse_value('["enemy", "damageable"]') returns list of strings."""

    def test_parse_int_array(self):
        """parse_value("[1, 2, 3]") returns list of ints."""

    def test_parse_dict(self):
        """parse_value with nested dict {"key": value} returns parsed dict."""


class TestTransform3DDecomposition:
    """Tests for Transform3D matrix decomposition into position/rotation/scale.

    Uses decompose_transform3d() which takes 12 floats and returns
    (position, rotation, scale) as three tuples.
    """

    def test_identity_transform(self):
        """Identity matrix: pos=(0,0,0), rot=(0,0,0), scale=(1,1,1)."""
        # Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)

    def test_translation_only(self):
        """Translation: pos=(-36.617, 0, -1.947), rot=(0,0,0), scale=(1,1,1)."""

    def test_uniform_scale(self):
        """Uniform scale 0.35: scale=(0.35, 0.35, 0.35)."""
        # Transform3D(0.35, 0, 0, 0, 0.35, 0, 0, 0, 0.35, 0, 0.326, 0)

    def test_non_uniform_scale(self):
        """Non-uniform scale Y=1.25: scale approx (1, 1.25, 1)."""
        # From main.tscn SouthWall: Transform3D(0.8887459, 0, 0, 0, 1.25, 0, 0, 0, 1, ...)

    def test_180_degree_y_rotation_with_scale(self):
        """180-degree Y rotation with scale: rot approx (0, pi, 0)."""
        # From main.tscn NorthWall: Transform3D(-1, 0, -1.509958e-07, 0, 1.25, 0, 1.509958e-07, 0, -1, ...)

    def test_scientific_notation_cleanup(self):
        """Scientific notation noise cleaned: -4.371139e-08 snaps to 0."""
        # From main.tscn WestWall: Transform3D(-4.371139e-08, 0, -1, 0, 1.25, 0, 1, 0, -4.371139e-08, ...)

    def test_90_degree_rotation(self):
        """90-degree Y rotation: rot approx (0, -pi/2, 0)."""
        # From main.tscn WestWall: the -4.371139e-08 pattern represents a 90-deg rotation

    def test_negative_determinant(self):
        """Negative determinant (mirrored): correct negative scale on one axis."""


class TestEdgeCases:
    """Edge cases for value parser."""

    def test_truefalse_not_bool(self):
        """parse_value("truefalse") does NOT match bool (not exact match)."""

    def test_empty_string(self):
        """parse_value with empty string returns empty string."""
```

Each test method should be a short, focused assertion. The test body should call `parse_value()` or `decompose_transform3d()` with the specified input and assert the expected output. Use `pytest.approx()` for floating-point comparisons in transform tests.

## Part 3: TSCN Parser Unit Tests

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

This file contains 23 unit tests organized by feature area. All tests call `parse_tscn(path)` with an absolute path to a fixture file. Use a `conftest.py` or compute paths from `Path(__file__)`.

Fixture path computation pattern:

```python
from pathlib import Path

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

The tests import `parse_tscn` from `godotiq.parsers.tscn_parser`.

```python
"""Unit tests for the TSCN parser — 23 tests covering all parser features."""

from pathlib import Path
import math
import pytest
from godotiq.parsers.tscn_parser import parse_tscn

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


class TestHeaderParsing:
    """2 tests: header format from worker.tscn and main.tscn."""

    def test_parse_header_format3(self):
        """worker.tscn has format=3."""
        scene = parse_tscn(str(FIXTURES / "worker.tscn"))
        assert scene.header.format == 3

    def test_parse_header_format4(self):
        """main.tscn has format=4."""
        scene = parse_tscn(str(FIXTURES / "main.tscn"))
        assert scene.header.format == 4


class TestResourceParsing:
    """2 tests: ext_resources and sub_resources."""

    def test_parse_ext_resources(self):
        """fdm_printer.tscn has 3 ext_resources with correct type, path, id."""
        scene = parse_tscn(str(FIXTURES / "fdm_printer.tscn"))
        assert len(scene.ext_resources) == 3
        # Verify one resource: id="1_iqbk5", type="Script", path ends with "printer.gd"
        res = scene.ext_resources["1_iqbk5"]
        assert res.type == "Script"
        assert res.path.endswith("printer.gd")

    def test_parse_sub_resources(self):
        """furniture_slot_placeholder.tscn has 3 sub_resources with parsed properties.

        Verifies that sub_resource property values are parsed as correct types:
        Color as tuple, Vector3 as tuple, int as int, float as float.
        """
        scene = parse_tscn(str(FIXTURES / "furniture_slot_placeholder.tscn"))
        assert len(scene.sub_resources) == 3
        # StandardMaterial3D sub_resource should have albedo_color as a tuple
        mat = scene.sub_resources["StandardMaterial3D_placeholder"]
        assert mat.type == "StandardMaterial3D"
        assert isinstance(mat.properties["albedo_color"], tuple)


class TestNodeParsing:
    """3 tests: basic nodes, hierarchy, deep nesting."""

    def test_parse_nodes_basic(self):
        """worker.tscn has exactly 4 nodes. Root is 'Worker' type 'CharacterBody3D'."""
        scene = parse_tscn(str(FIXTURES / "worker.tscn"))
        assert len(scene.nodes) == 4
        assert scene.root.name == "Worker"
        assert scene.root.type == "CharacterBody3D"

    def test_parse_node_hierarchy(self):
        """fdm_printer.tscn: root 'FDMPrinter' has correct number of direct children."""
        scene = parse_tscn(str(FIXTURES / "fdm_printer.tscn"))
        # FDMPrinter has 5 direct children: StaticBody3D, PrinterModel, FilamentSpool, WorkPoint
        # and StaticBody3D has 1 child: CollisionShape3D
        assert scene.root.name == "FDMPrinter"
        child_names = [c.name for c in scene.root.children]
        assert "StaticBody3D" in child_names
        assert "PrinterModel" in child_names

    def test_parse_deep_nesting(self):
        """main.tscn: a node at 6+ levels deep is reachable via find_node."""
        scene = parse_tscn(str(FIXTURES / "main.tscn"))
        # Building/LockedZones/PostProcessingZone/PostProcessingFloor/FloorTile_0_0/floorFull(Clone)2
        node = scene.find_node("Building/LockedZones/PostProcessingZone/PostProcessingFloor/FloorTile_0_0/floorFull(Clone)2")
        assert node is not None
        assert node.name == "floorFull(Clone)2"


class TestGroups:
    """2 tests: single group and multiple groups."""

    def test_parse_groups_single(self):
        """fdm_printer.tscn: FDMPrinter node has group 'interactable'."""
        scene = parse_tscn(str(FIXTURES / "fdm_printer.tscn"))
        assert "interactable" in scene.root.groups

    def test_parse_groups_multiple(self):
        """main.tscn: filament_storage node has two groups ['material_store', 'storage_points']."""
        scene = parse_tscn(str(FIXTURES / "main.tscn"))
        nodes = scene.get_nodes_by_group("material_store")
        storage_node = next(n for n in nodes if n.name == "filament_storage")
        assert "material_store" in storage_node.groups
        assert "storage_points" in storage_node.groups


class TestTransforms:
    """5 tests: identity/translation, uniform scale, non-uniform scale, rotation, scientific notation."""

    def test_parse_transform_identity_with_translation(self):
        """worker.tscn: CollisionShape3D has position=(0, 0.5, 0), rot=(0,0,0), scale=(1,1,1)."""
        scene = parse_tscn(str(FIXTURES / "worker.tscn"))
        node = scene.find_node("CollisionShape3D")
        assert node is not None
        assert node.position == pytest.approx((0.0, 0.5, 0.0))
        assert node.rotation == pytest.approx((0.0, 0.0, 0.0))
        assert node.scale == pytest.approx((1.0, 1.0, 1.0))

    def test_parse_transform_uniform_scale(self):
        """fdm_printer.tscn: PrinterModel has scale approx (0.35, 0.35, 0.35)."""
        scene = parse_tscn(str(FIXTURES / "fdm_printer.tscn"))
        node = scene.find_node("PrinterModel")
        assert node is not None
        assert node.scale == pytest.approx((0.35, 0.35, 0.35))

    def test_parse_transform_nonuniform_scale(self):
        """main.tscn: SouthWall_X2 has non-uniform scale with Y=1.25.

        Transform3D(0.8887459, 0, 0, 0, 1.25, 0, 0, 0, 1, -35.617043, 0, -9.447166)
        Scale X is 0.8887459, Y is 1.25, Z is 1.0.
        """
        scene = parse_tscn(str(FIXTURES / "main.tscn"))
        node = scene.find_node("Building/Walls/ExteriorWalls/SouthWall_X2")
        assert node is not None
        assert node.scale[1] == pytest.approx(1.25)

    def test_parse_transform_rotation(self):
        """main.tscn: NorthWall_X0 has 180-degree Y rotation.

        Transform3D(-1, 0, -1.509958e-07, 0, 1.25, 0, 1.509958e-07, 0, -1, ...)
        After decomposition, rotation Y should be approx pi.
        """
        scene = parse_tscn(str(FIXTURES / "main.tscn"))
        node = scene.find_node("Building/Walls/ExteriorWalls/NorthWall_X0")
        assert node is not None
        assert abs(node.rotation[1]) == pytest.approx(math.pi, abs=0.01)

    def test_parse_transform_scientific_notation(self):
        """main.tscn: WestWall nodes have -4.371139e-08 values that should be cleaned.

        Transform3D(-4.371139e-08, 0, -1, 0, 1.25, 0, 1, 0, -4.371139e-08, ...)
        This represents a 90-degree rotation. The tiny values should snap to zero
        during decomposition so rotation is clean.
        """
        scene = parse_tscn(str(FIXTURES / "main.tscn"))
        node = scene.find_node("Building/Walls/ExteriorWalls/WestWall_Z3")
        assert node is not None
        # After cleaning scientific notation noise, rotation Y should be approx -pi/2
        assert node.rotation[1] == pytest.approx(-math.pi / 2, abs=0.01)


class TestNodeAttributes:
    """3 tests: instance, script, node without type."""

    def test_parse_instance_node(self):
        """fdm_printer.tscn: PrinterModel has instance (ExtResource ref id '2_model')."""
        scene = parse_tscn(str(FIXTURES / "fdm_printer.tscn"))
        node = scene.find_node("PrinterModel")
        assert node is not None
        assert node.instance == "2_model"

    def test_parse_script_assignment(self):
        """worker.tscn: root node has script pointing to ExtResource '1_qf3b7'."""
        scene = parse_tscn(str(FIXTURES / "worker.tscn"))
        assert scene.root.script == "1_qf3b7"

    def test_parse_node_without_type(self):
        """fdm_printer.tscn: PrinterModel has instance but no explicit type attribute."""
        scene = parse_tscn(str(FIXTURES / "fdm_printer.tscn"))
        node = scene.find_node("PrinterModel")
        assert node is not None
        # Node has instance but type is empty string (no type= in header)
        assert node.type == ""


class TestPropertiesAndMetadata:
    """3 tests: custom properties, metadata, value types from fixture."""

    def test_parse_custom_properties(self):
        """main.tscn: PostProcessingZone has zone_name, unlock_cost, tier_required."""
        scene = parse_tscn(str(FIXTURES / "main.tscn"))
        node = scene.find_node("Building/LockedZones/PostProcessingZone")
        assert node is not None
        assert node.properties["zone_name"] == "Post-Processing"
        assert node.properties["unlock_cost"] == 5000
        assert node.properties["tier_required"] == 2

    def test_parse_metadata(self):
        """main.tscn: ResearchDesk has metadata/station_type = 'desk'.

        The 'metadata/' prefix is stripped and the value stored in node.metadata dict.
        """
        scene = parse_tscn(str(FIXTURES / "main.tscn"))
        node = scene.find_node("RDLabZone/ResearchDesk")
        assert node is not None
        assert node.metadata["station_type"] == "desk"

    def test_parse_value_types(self):
        """furniture_slot_placeholder.tscn: sub_resources have Color, Vector3, int, float all parsed.

        StandardMaterial3D has transparency (int), albedo_color (Color tuple), billboard (int).
        BoxMesh has size (Vector3 tuple).
        """
        scene = parse_tscn(str(FIXTURES / "furniture_slot_placeholder.tscn"))
        mat = scene.sub_resources["StandardMaterial3D_placeholder"]
        assert isinstance(mat.properties["transparency"], int)
        assert isinstance(mat.properties["albedo_color"], tuple)
        assert len(mat.properties["albedo_color"]) == 4
        box_mesh = scene.sub_resources["BoxMesh_placeholder"]
        assert isinstance(box_mesh.properties["size"], tuple)
        assert len(box_mesh.properties["size"]) == 3


class TestEdgeCases:
    """3 tests: special node names, stress node count, stress ext_resource count."""

    def test_parse_special_node_names(self):
        """main.tscn: '@CSGBox3D@106885' is parsed correctly as a node name."""
        scene = parse_tscn(str(FIXTURES / "main.tscn"))
        # The node is a direct child of root (parent=".")
        node = scene.find_node("@CSGBox3D@106885")
        assert node is not None
        assert node.name == "@CSGBox3D@106885"
        assert node.type == "CSGBox3D"

    def test_node_count_stress(self):
        """main.tscn has exactly 876 nodes."""
        scene = parse_tscn(str(FIXTURES / "main.tscn"))
        assert len(scene.nodes) == 876

    def test_ext_resource_count_stress(self):
        """main.tscn has exactly 68 ext_resources."""
        scene = parse_tscn(str(FIXTURES / "main.tscn"))
        assert len(scene.ext_resources) == 68
```

## Part 4: Conftest for Parser Tests (optional helper)

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

If shared pytest fixtures are useful for the parser test directory, create a minimal conftest:

```python
"""Shared fixtures for parser tests."""

from pathlib import Path
import pytest
from godotiq.parsers.tscn_parser import parse_tscn

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


@pytest.fixture(scope="module")
def worker_scene():
    """Parse worker.tscn once per module."""
    return parse_tscn(str(FIXTURES / "worker.tscn"))


@pytest.fixture(scope="module")
def fdm_printer_scene():
    """Parse fdm_printer.tscn once per module."""
    return parse_tscn(str(FIXTURES / "fdm_printer.tscn"))


@pytest.fixture(scope="module")
def furniture_slot_scene():
    """Parse furniture_slot_placeholder.tscn once per module."""
    return parse_tscn(str(FIXTURES / "furniture_slot_placeholder.tscn"))


@pytest.fixture(scope="module")
def main_scene():
    """Parse main.tscn once per module (expensive, cached per module)."""
    return parse_tscn(str(FIXTURES / "main.tscn"))
```

Using `scope="module"` avoids re-parsing the 4711-line `main.tscn` for every single test. Tests can either use these fixtures or call `parse_tscn` directly -- both patterns are valid.

## Implementation Checklist

1. Create `/Users/salvatorefarruggio/Desktop/godotiq/tests/fixtures/furniture_slot_placeholder.tscn` with exactly 37 lines, 6 nodes, and 3 sub_resources containing Color, Vector3, int, and float properties.

2. Create `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_parsers/test_value_parser.py` with all test classes and methods listed above. Each test method calls `parse_value()` or `decompose_transform3d()` with specific inputs and asserts expected outputs. Use `pytest.approx()` for float comparisons.

3. Create `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_parsers/test_tscn_parser.py` with all 23 tests organized in the classes shown above. Each test calls `parse_tscn(path)` with an absolute path to a fixture and asserts specific properties of the returned `TscnScene`.

4. Optionally create `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_parsers/conftest.py` with module-scoped fixtures to avoid redundant parsing in tests.

5. Run `pytest tests/test_parsers/test_value_parser.py tests/test_parsers/test_tscn_parser.py -v` to confirm all tests pass.

## Key Data Points for Tests (from Fixture Inspection)

These verified facts from the actual fixture files inform the test assertions:

**worker.tscn:**
- Header: `format=3`, `uid="uid://c38r6godkoupy"`
- 1 ext_resource: `id="1_qf3b7"`, type="Script", path ends with `worker.gd`
- 1 sub_resource: `id="CapsuleShape3D_qf3b7"`, type="CapsuleShape3D"
- 4 nodes: Worker (root, CharacterBody3D), CollisionShape3D, WorkerModel, CarryPoint
- Root has `script = ExtResource("1_qf3b7")`
- CollisionShape3D transform: `Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)` -- position (0, 0.5, 0)

**fdm_printer.tscn:**
- Header: `format=3`
- 3 ext_resources: Script (printer.gd), PackedScene (printer_standard.glb), PackedScene (filament_spool.glb)
- 1 sub_resource: BoxShape3D with `size = Vector3(0.7, 0.65, 0.56)`
- 6 nodes: FDMPrinter (root), StaticBody3D, CollisionShape3D, PrinterModel, FilamentSpool, WorkPoint
- FDMPrinter has `groups=["interactable"]`
- PrinterModel: `instance=ExtResource("2_model")`, no explicit type, transform scale (0.35, 0.35, 0.35)

**main.tscn:**
- Header: `format=4`
- 68 ext_resources, 142 sub_resources (verified by grep count)
- 876 nodes (verified by grep count)
- Root node: `name="Main"`, `type="Node3D"`
- PostProcessingZone: properties `zone_name="Post-Processing"`, `unlock_cost=5000`, `tier_required=2`
- ResearchDesk: `metadata/station_type = "desk"`, groups `["interactable", "research_stations"]`
- filament_storage: groups `["material_store", "storage_points"]`
- 6 printer_slots nodes in group `"printer_slots"`
- @CSGBox3D@106885: type CSGBox3D, parent="." (direct child of root)
- SouthWall_X2 transform: `Transform3D(0.8887459, 0, 0, 0, 1.25, 0, 0, 0, 1, -35.617043, 0, -9.447166)` -- non-uniform scale
- NorthWall_X0 transform: `Transform3D(-1, 0, -1.509958e-07, 0, 1.25, 0, 1.509958e-07, 0, -1, ...)` -- 180-degree Y rotation
- WestWall_Z3 transform: `Transform3D(-4.371139e-08, 0, -1, 0, 1.25, 0, 1, 0, -4.371139e-08, ...)` -- 90-degree Y rotation with scientific notation noise
- Deep nesting path: `Building/LockedZones/PostProcessingZone/PostProcessingFloor/FloorTile_0_0/floorFull(Clone)2`

## Notes on Return Types from Value Parser

Tests need to know what type `parse_value()` returns for reference types. The plan specifies:

- `ExtResource("id")` -- the return type must encode the ID string. The implementation may return a dict like `{"ext_resource": "id"}`, a named tuple, or a string. Tests for the TSCN parser check `node.script` and `node.instance` which store just the ID string (extracted by the state machine). The value parser test for `parse_value('ExtResource("1_abc")')` should assert the ID `"1_abc"` is extractable from the result.

- `SubResource("id")` -- same pattern. The value parser returns something from which the ID can be extracted.

The exact return representation (dict, dataclass, or tagged string) is an implementation detail from Section 01. The tests should assert based on whatever convention was chosen. If `parse_value` returns a dict like `{"type": "ext_resource", "id": "1_abc"}`, test accordingly. If it returns just the string ID, test that.