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

# Section 4: Add detail to Spatial Tools

## Overview

This section adds the `detail` parameter to the `placement` tool in `src/godotiq/tools/spatial/__init__.py`. The `placement` tool returns placement suggestions for new objects. It currently lacks the `detail` parameter that the other spatial tools (`scene_map`, `spatial_audit`) already have.

The change is small: add `detail: str = "normal"` to the function signature, update the docstring, and apply `apply_output_limit()` on the result. For `brief` mode, the output is further reduced to return only the top suggestion with position and confidence (stripping clearance, excluded zones, and scale reasoning).

## Dependencies

- **Section 1 (output_limit.py enhancements)** must be completed first. This section depends on the input validation added to `apply_output_limit()` so that unknown `detail` values normalize to `"normal"` instead of falling through to unlimited.

## File to Modify

**`/Users/salvatorefarruggio/Desktop/godotiq/src/godotiq/tools/spatial/__init__.py`**

Only the `godotiq_placement` wrapper function needs changes. The sub-module `placement.py` (`compute_placement`) is NOT modified -- it continues to return full data. Filtering happens in the `__init__.py` wrapper after receiving the result.

## Tests (Write First)

Tests go in `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_tools/test_detail_levels.py` (shared test file for all per-tool detail tests; this section only contributes the placement-related tests).

Since `godotiq_placement` is an async MCP tool that requires a `ctx` with a session, the tests should call `compute_placement` directly from the sub-module (as existing `test_placement.py` does), then verify that `apply_output_limit()` produces the expected truncation behavior. Alternatively, tests can construct a result dict matching the `compute_placement` return format and pass it through `apply_output_limit()`.

Test stubs for this section:

```python
# Test: placement accepts detail parameter without error
# Verify the function signature of godotiq_placement includes detail: str = "normal"
# Use inspect.signature to confirm the parameter exists and has the correct default.

# Test: placement default (no detail) returns dict
# Call compute_placement with a simple scene (marker + reference node).
# The result should be a dict with "suggestions" key.
# Wrap with apply_output_limit(result, "normal", list_keys=["suggestions", "excluded_zones"])
# and confirm the output is a dict.

# Test: placement brief output under 3000 chars
# Build a result dict that mimics a large compute_placement response 
# (many suggestions, large excluded_zones list).
# Apply apply_output_limit(result, "brief", list_keys=["suggestions", "excluded_zones"]).
# Measure JSON output length; assert it is under 3000 chars.

# Test: placement normal output under 10000 chars
# Same approach with detail="normal". Assert output under 10000 chars.
```

These 3000/10000 char thresholds include buffer over the raw limits (2000/8000) to account for metadata overhead from `apply_output_limit()`.

## Implementation Details

### 1. Add `detail` parameter to `godotiq_placement`

In the `godotiq_placement` async function (currently at line ~821), add `detail: str = "normal"` to the parameter list. Place it after `max_suggestions` and before `ctx`.

Updated signature:

```python
async def godotiq_placement(
    scene: str = "",
    near: str = "",
    near_position: list[float] | None = None,
    object_type: str = "",
    constraints: dict | None = None,
    max_suggestions: int = 3,
    detail: str = "normal",
    ctx: Context = None,
) -> dict:
```

### 2. Update the docstring

Add to the Args section of the docstring:

```
detail: Output verbosity -- "brief" (summary), "normal" (default), or "full" (everything).
```

### 3. Apply `apply_output_limit()` on the result

After `compute_placement()` returns, apply output limiting before returning. The `compute_placement` return dict has these keys with list values that can be truncated:
- `"suggestions"` -- list of placement suggestion dicts
- `"excluded_zones"` -- list of zone dicts

The implementation should:

1. Call `compute_placement(...)` to get the full result (unchanged).
2. For `brief` mode specifically, strip less essential fields from each suggestion to keep output compact. Specifically, in brief mode, keep only `position` and `confidence` in each suggestion, and omit `excluded_zones` and `scale_reasoning` entirely. This gives a minimal overview.
3. Apply `apply_output_limit(result, detail, list_keys=["suggestions", "excluded_zones"])` as a safety net truncation.
4. Return the result.

The brief-mode field stripping should happen **before** calling `apply_output_limit()`, since `apply_output_limit()` only truncates list length (number of items), not individual fields within list items.

Implementation pattern in the wrapper:

```python
result = compute_placement(
    world_nodes=nodes,
    near=near,
    near_position=near_position,
    object_type=object_type,
    constraints=constraints,
    max_suggestions=max_suggestions,
)

if detail == "brief" and "suggestions" in result:
    result["suggestions"] = [
        {"position": s["position"], "confidence": s["confidence"]}
        for s in result["suggestions"][:1]  # Top suggestion only
    ]
    result.pop("excluded_zones", None)
    result.pop("scale_reasoning", None)

return apply_output_limit(result, detail, list_keys=["suggestions", "excluded_zones"])
```

### 4. No changes to `placement.py` sub-module

The `compute_placement` function in `/Users/salvatorefarruggio/Desktop/godotiq/src/godotiq/tools/spatial/placement.py` is NOT modified. It continues to return the full result dict with all suggestions, excluded zones, and scale reasoning. The filtering is applied in the `__init__.py` wrapper.

## Behavioral Summary by Detail Level

| Level | Suggestions | Fields per Suggestion | Excluded Zones | Scale Reasoning |
|-------|-------------|----------------------|----------------|-----------------|
| `brief` | Top 1 only | position, confidence only | Omitted | Omitted |
| `normal` | Up to max_suggestions (default 3) | All fields (position, rotation_deg, scale, confidence, reason, clearance, source) | Included | Included |
| `full` | Up to max_suggestions | All fields | Included | Included |

For `normal` and `full`, the output is identical to current behavior (both pass through `apply_output_limit()` as a safety net, but the placement tool's output is naturally small enough that truncation rarely activates).

## Verification

After implementation, verify:
1. `pytest tests/test_tools/test_placement.py -v` -- all existing placement tests still pass (no regressions).
2. The `godotiq_placement` function's `inspect.signature` shows `detail` parameter with default `"normal"`.
3. Calling `compute_placement` with a small scene and wrapping with `apply_output_limit(..., "brief", ...)` produces output under 2000 chars.