# Opus Review

**Model:** claude-opus-4
**Generated:** 2026-03-08

---

## Overall Assessment

The plan is well-structured and clearly scoped. The problem is real and well-quantified (140k chars from a single tool call against a ~200k token context window). The approach of leveraging the existing `apply_output_limit()` infrastructure rather than rewriting output formats is pragmatic. However, there are several issues ranging from factual inaccuracies to architectural concerns that need to be addressed before implementation.

## Critical Issues

### 1. Tool count is wrong -- the plan misses `ping` and `exec`
The research says "32 MCP tools" and identifies 17 with detail + 14 without = 31, noting "ping is trivial." The plan says "32 tools" and claims "13 tools need detail added," but the table lists 14. The plan also never mentions whether `exec` or `ping` should get detail. Since success criteria is "32/32," this needs resolution.

### 2. The `impact_check` rename has a subtle data regression
The current `detail` parameter is included in the returned result dict (echoed back) and used in string interpolation for `safe_alternative` message. After renaming, both the output dict field and the string interpolation need updating.

### 3. `apply_output_limit` is never applied to `impact_check` currently
Adding it changes the output format (adds potential `output_truncated`, `truncation_notice`, `callers_total` fields). This is a behavioral change.

## Architectural Concerns

### 4. Bridge tools: `detail` does not flow to sub-modules
Actual logic lives in separate sub-modules (file_ops.py, node_ops.py, etc.). Plan should specify whether apply_output_limit is applied in __init__.py wrapper or inside each sub-module.

### 5. `truncate_output()` has no callers identified
All 32 tools return dict types. The function appears to solve a problem that doesn't exist. If future-proofing, say so.

### 6. `full` level: 200k limit in truncate_output contradicts unlimited in apply_output_limit
Design conflict. Either both unlimited for full, or justify the asymmetry.

## Edge Cases

### 7. apply_output_limit measures JSON-serialized size with metadata overhead
Tests should account for metadata overhead in size assertions.

### 8. apply_output_limit only truncates lists -- large string values unhandled
file_ops with op="read" returns {"content": text} where text could be entire file. apply_output_limit won't truncate it.

### 9. node_ops returns results from Godot bridge
Response schema key names aren't documented. Can't specify list_keys without knowing the schema.

### 10. No validation of detail parameter value
Unknown values like "verbose" silently fall through to no-limit behavior.

### 11. config.get_default_detail() is never used
Every tool has detail hardcoded as "normal". Config setting has no effect.

## Missing Considerations

### 12. Backward compatibility for MCP schema
Renaming impact_check parameter is a breaking change. Should be acknowledged.

### 13. scene_map full caps at 30 nodes for performance
Cap prevents O(n^2) distance matrix explosion. Removing it needs performance consideration.

### 14. No ordering/prioritization for Section 6 work

### 15. Integration test needs large enough fixtures to trigger truncation

### 16. apply_output_limit calls json.dumps multiple times during binary search (performance)

## Minor Issues

### 17. File modification table incomplete (missing sub-module files)
### 18. ping tool not in modification summary
### 19. Research mentions head-tail truncation but plan uses only head truncation
### 20. truncate_output line count unhelpful for single-line JSON

## Recommendations

1. Fix tool count arithmetic, explicitly list every tool
2. Clarify where apply_output_limit is called for bridge tools (wrapper vs sub-module)
3. Address impact_check output dict field naming conflict
4. Either remove truncate_output from scope or identify callers
5. Harmonize full detail level behavior
6. Add detail parameter validation
7. Address file_ops op="read" specifically
8. Document whether config.get_default_detail() should be wired in
