test(mcp): Villa Azul + 10-agent deep verification
Builds a larger, richer house than Casa del Sol via MCP save_scene (no injection hack), then dispatches 10 parallel verifiers across schema, geometry, dimensions, openings, HTTP, page render, parentage, round-trip, spatial, visual. Villa Azul — 56 nodes, validate_scene=true, 44KB on disk: - 15x10m building envelope (vs Casa del Sol's 12x8) - 9 interior zones (master bed/bath, bed 2/3, shared bath, living/dining, kitchen, entry hall, corridor) - 10 doors + 12 windows (all cut successfully) - 4 exterior zones (pool 8x4 + basin slab at -2m, outdoor kitchen, driveway, back patio) - 5 rail-style fences (vs Casa del Sol's privacy) with 2m entrance gap Verification: 108 checks, 104 PASS, 4 findings: - V1 schema: 56/56 - V2 geometry: 7/7 (perimeter closes, interior T-junctions, no zone overlaps, fence gap verified) - V3 dimensions: 13/13 zone areas exact (1 spec mismatch on site polygon default, not a build bug) - V4 openings: 22/22 dimensional fit, surfaced a tool gap in cut_opening (no adjacency check) + my build packed too tightly - V5 HTTP: 10/10 (GET/PUT/PATCH/DELETE/HEAD, If-Match conflicts) - V6 page: 14/14 (/scene/:id 81KB, /scenes 20KB, 404 fallback) - V7 parentage: surfaced CROSS_CUTTING §2 site->building->level parentId=null (pre-existing in core's loadScene) - V8 round-trip: 10/10 byte-equal, duplicate_level -> 110 nodes - V9 spatial: 12/12 (find_nodes, measure, constraints resource) - V10 visual: HTML fallback (Chrome extension disconnected during run); API layer intact Follow-up tracked: `cut_opening` should check opening-adjacency on the same wall (minimum gap) to catch tight packing during patch construction. Currently returns success and relies on the UI to visualise the overlap. Live at http://localhost:3002/scene/a6e7919eacbe. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
0b84e7b7b1
commit
f230d9a401
@@ -0,0 +1,66 @@
|
||||
# Villa Azul — V8 Load-Save Round-Trip Report
|
||||
|
||||
- Generated: 2026-04-19T18:37:01.857Z
|
||||
- Shared source: `/tmp/pascal-villa/scenes/a6e7919eacbe.json`
|
||||
- Isolated data dir: `/tmp/pascal-villa-v8`
|
||||
- Transport: stdio (`bun /Users/adrian/Desktop/editor/.worktrees/mcp-server/packages/mcp/dist/bin/pascal-mcp.js --stdio`)
|
||||
- New sceneId (copy): `d346bd83beb9`
|
||||
- Rebuilt sceneId (apply_patch): `0a264e09564f`
|
||||
- Duplicated sceneId: `db09cfe4a8fc`
|
||||
|
||||
## Original node-type counts
|
||||
|
||||
| Type | Count |
|
||||
|---|---:|
|
||||
| building | 1 |
|
||||
| door | 10 |
|
||||
| fence | 5 |
|
||||
| level | 1 |
|
||||
| site | 1 |
|
||||
| slab | 1 |
|
||||
| wall | 12 |
|
||||
| window | 12 |
|
||||
| zone | 13 |
|
||||
| **total** | **56** |
|
||||
|
||||
## Results
|
||||
|
||||
| # | Check | Status | Detail |
|
||||
|---|---|:---:|---|
|
||||
| 1 | 1.read-original | PASS | nodes=56, roots=1, types={"site":1,"building":1,"level":1,"wall":12,"zone":13,"door":10,"window":12,"slab":1,"fence":5} |
|
||||
| 2 | 2.spawn-isolated-stdio | PASS | PASCAL_DATA_DIR=/tmp/pascal-villa-v8 |
|
||||
| 3 | 3.save_scene(copy) | PASS | id=d346bd83beb9 version=1 nodes=56 bytes=44285 |
|
||||
| 4 | 4a.load→get_scene ids preserved | PASS | 56 ids, match=true |
|
||||
| 5 | 4b.load→get_scene rootNodeIds | PASS | orig=[site_5mzaasm5o9a9d0sf] loaded=[site_5mzaasm5o9a9d0sf] |
|
||||
| 6 | 4c.load→get_scene deep-equal per-node | PASS | diffs=0 |
|
||||
| 7 | 5.apply_patch rebuild counts | PASS | ops=53 created=53 total=56 diffs=none |
|
||||
| 8 | 6.duplicate_level + save + reload counts | PASS | valid=true new=54 total=110 diffs=none |
|
||||
| 9 | 7.stableStringify(orig.nodes) === stableStringify(reloaded.nodes) | PASS | orig=23333ch reloaded=23333ch equal=true |
|
||||
| 10 | 7b.on-disk isolated file graph === shared file graph | PASS | path=/tmp/pascal-villa-v8/scenes/d346bd83beb9.json equal=true |
|
||||
|
||||
## Summary
|
||||
|
||||
- Passed: **10/10**
|
||||
- Failed: **0/10**
|
||||
- Overall: **PASS**
|
||||
|
||||
## Original vs loaded-after-save — per-type count diff
|
||||
|
||||
| Type | Original | Loaded | Match |
|
||||
|---|---:|---:|:---:|
|
||||
| building | 1 | 1 | YES |
|
||||
| door | 10 | 10 | YES |
|
||||
| fence | 5 | 5 | YES |
|
||||
| level | 1 | 1 | YES |
|
||||
| site | 1 | 1 | YES |
|
||||
| slab | 1 | 1 | YES |
|
||||
| wall | 12 | 12 | YES |
|
||||
| window | 12 | 12 | YES |
|
||||
| zone | 13 | 13 | YES |
|
||||
|
||||
## Notes
|
||||
|
||||
- `save_scene({ includeCurrentScene: false, graph })` should persist the graph verbatim, preserving all node ids.
|
||||
- `stableStringify` normalises key order so byte equality is order-independent; this is the canonical "deep-equal" check here.
|
||||
- Step 5 rebuilds the scene by save/load-ing a shell (site+building+level) then replaying every remaining node as an `apply_patch` `create` op. Only counts-per-type are compared (node ids on the rebuild will equal the originals because we reuse the same ids in the patches).
|
||||
- Step 6 exercises `duplicate_level` against the copied scene; the site/building remain shared (count=1), while per-level types should double.
|
||||
Reference in New Issue
Block a user