fix(mcp): apply_patch preserves schema-defaulted ids in multi-op batches

SceneBridge.applyPatch now threads the Zod-parsed node through to the
apply phase instead of the raw input. Previously, when a caller sent a
create patch without an `id` field, the schema's objectId default ran
during dry-run parsing but only in `res.data`; the apply phase pushed
the unparsed `p.node` (no id) to the store, so subsequent tools that
walked `level.children` crashed on undefined entries (e.g.
duplicate_level -> cloneLevelSubtree -> extractIdPrefix(undefined)).

Also adds test-reports/ artefacts from live end-to-end testing:
- t1-stdio: 21/21 tools pass via stdio (~106ms)
- t2-http: connect/single-session behaviour (HTTP transport quirk
  documented)
- t3-scenario: 2-bedroom apartment built end-to-end — 12/12 steps
  after this fix (24 final nodes, validate=true, apartment.json
  exported)
- t4-errors: 24/24 invalid-input cases rejected with proper MCP errors
- t5-resources-prompts: 4/4 resources, 3/3 prompts, dev server
  /api/health 200 OK

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adrian Perez
2026-04-18 18:21:00 +02:00
co-authored by Claude Opus 4.7
parent a6f1c4140f
commit b37e88cb83
19 changed files with 5884 additions and 4 deletions
@@ -0,0 +1,772 @@
{
"nodes": {
"site_xs1r72ib2ymzpjus": {
"object": "node",
"id": "site_xs1r72ib2ymzpjus",
"type": "site",
"parentId": null,
"visible": true,
"metadata": {},
"polygon": {
"type": "polygon",
"points": [
[
-15,
-15
],
[
15,
-15
],
[
15,
15
],
[
-15,
15
]
]
},
"children": [
{
"object": "node",
"id": "building_bfqg91ai9ijps9ej",
"type": "building",
"parentId": null,
"visible": true,
"metadata": {},
"children": [
"level_wyuoxj87czq3v0re"
],
"position": [
0,
0,
0
],
"rotation": [
0,
0,
0
]
}
]
},
"building_bfqg91ai9ijps9ej": {
"object": "node",
"id": "building_bfqg91ai9ijps9ej",
"type": "building",
"parentId": null,
"visible": true,
"metadata": {},
"children": [
"level_wyuoxj87czq3v0re"
],
"position": [
0,
0,
0
],
"rotation": [
0,
0,
0
]
},
"level_wyuoxj87czq3v0re": {
"object": "node",
"id": "level_wyuoxj87czq3v0re",
"type": "level",
"parentId": null,
"visible": true,
"metadata": {},
"children": [
"wall_y87bsrljd2245n51",
"wall_sja6jpda73tlhxwb",
"wall_aegff27krjwgmkmi",
"wall_dcymglyle9ff09ti",
"wall_rl83cc5tnbf4b34j",
"wall_qv53jm9kvl7k6slf",
"wall_8y52fwzco2ep7fb1",
"wall_hrfixeusz7zb7x63",
"wall_1ullk9bm6dw15i9t",
"wall_c4fjjswnk0mprctm",
"wall_p359pffjf3qs59cy",
"zone_3fyksm10tb0dhn1e",
"zone_u95l1bt35jci3gvu",
"zone_r9ma8tvsqt9w1zey",
"zone_l189q61kf9ra2m8t"
],
"level": 0
},
"wall_y87bsrljd2245n51": {
"object": "node",
"id": "wall_y87bsrljd2245n51",
"type": "wall",
"parentId": "level_wyuoxj87czq3v0re",
"visible": true,
"metadata": {},
"children": [
"window_47x40mtv2l4ca9p4",
"window_n09awmg5m3ct4fvn"
],
"thickness": 0.2,
"height": 2.7,
"start": [
0,
0
],
"end": [
10,
0
],
"frontSide": "unknown",
"backSide": "unknown"
},
"wall_sja6jpda73tlhxwb": {
"object": "node",
"id": "wall_sja6jpda73tlhxwb",
"type": "wall",
"parentId": "level_wyuoxj87czq3v0re",
"visible": true,
"metadata": {},
"children": [],
"thickness": 0.2,
"height": 2.7,
"start": [
10,
0
],
"end": [
10,
8
],
"frontSide": "unknown",
"backSide": "unknown"
},
"wall_aegff27krjwgmkmi": {
"object": "node",
"id": "wall_aegff27krjwgmkmi",
"type": "wall",
"parentId": "level_wyuoxj87czq3v0re",
"visible": true,
"metadata": {},
"children": [
"window_xlta3f3f0cnmbti3"
],
"thickness": 0.2,
"height": 2.7,
"start": [
10,
8
],
"end": [
0,
8
],
"frontSide": "unknown",
"backSide": "unknown"
},
"wall_dcymglyle9ff09ti": {
"object": "node",
"id": "wall_dcymglyle9ff09ti",
"type": "wall",
"parentId": "level_wyuoxj87czq3v0re",
"visible": true,
"metadata": {},
"children": [],
"thickness": 0.2,
"height": 2.7,
"start": [
0,
8
],
"end": [
0,
0
],
"frontSide": "unknown",
"backSide": "unknown"
},
"wall_rl83cc5tnbf4b34j": {
"object": "node",
"id": "wall_rl83cc5tnbf4b34j",
"type": "wall",
"parentId": "level_wyuoxj87czq3v0re",
"visible": true,
"metadata": {},
"children": [],
"thickness": 0.2,
"height": 2.7,
"start": [
0,
5
],
"end": [
3,
5
],
"frontSide": "unknown",
"backSide": "unknown"
},
"wall_qv53jm9kvl7k6slf": {
"object": "node",
"id": "wall_qv53jm9kvl7k6slf",
"type": "wall",
"parentId": "level_wyuoxj87czq3v0re",
"visible": true,
"metadata": {},
"children": [
"door_cjzja4lt8owg88wg"
],
"thickness": 0.2,
"height": 2.7,
"start": [
3,
5
],
"end": [
3,
8
],
"frontSide": "unknown",
"backSide": "unknown"
},
"wall_8y52fwzco2ep7fb1": {
"object": "node",
"id": "wall_8y52fwzco2ep7fb1",
"type": "wall",
"parentId": "level_wyuoxj87czq3v0re",
"visible": true,
"metadata": {},
"children": [],
"thickness": 0.2,
"height": 2.7,
"start": [
7,
5
],
"end": [
10,
5
],
"frontSide": "unknown",
"backSide": "unknown"
},
"wall_hrfixeusz7zb7x63": {
"object": "node",
"id": "wall_hrfixeusz7zb7x63",
"type": "wall",
"parentId": "level_wyuoxj87czq3v0re",
"visible": true,
"metadata": {},
"children": [
"door_bs7bf0azevq9vd76"
],
"thickness": 0.2,
"height": 2.7,
"start": [
7,
5
],
"end": [
7,
8
],
"frontSide": "unknown",
"backSide": "unknown"
},
"wall_1ullk9bm6dw15i9t": {
"object": "node",
"id": "wall_1ullk9bm6dw15i9t",
"type": "wall",
"parentId": "level_wyuoxj87czq3v0re",
"visible": true,
"metadata": {},
"children": [
"door_o8etwqsemfgj5mkj"
],
"thickness": 0.2,
"height": 2.7,
"start": [
4,
6
],
"end": [
6,
6
],
"frontSide": "unknown",
"backSide": "unknown"
},
"wall_c4fjjswnk0mprctm": {
"object": "node",
"id": "wall_c4fjjswnk0mprctm",
"type": "wall",
"parentId": "level_wyuoxj87czq3v0re",
"visible": true,
"metadata": {},
"children": [],
"thickness": 0.2,
"height": 2.7,
"start": [
4,
6
],
"end": [
4,
8
],
"frontSide": "unknown",
"backSide": "unknown"
},
"wall_p359pffjf3qs59cy": {
"object": "node",
"id": "wall_p359pffjf3qs59cy",
"type": "wall",
"parentId": "level_wyuoxj87czq3v0re",
"visible": true,
"metadata": {},
"children": [],
"thickness": 0.2,
"height": 2.7,
"start": [
6,
6
],
"end": [
6,
8
],
"frontSide": "unknown",
"backSide": "unknown"
},
"zone_3fyksm10tb0dhn1e": {
"object": "node",
"id": "zone_3fyksm10tb0dhn1e",
"type": "zone",
"name": "bedroom-1",
"parentId": "level_wyuoxj87czq3v0re",
"visible": true,
"metadata": {},
"polygon": [
[
0,
5
],
[
3,
5
],
[
3,
8
],
[
0,
8
]
],
"color": "#3b82f6"
},
"zone_u95l1bt35jci3gvu": {
"object": "node",
"id": "zone_u95l1bt35jci3gvu",
"type": "zone",
"name": "bedroom-2",
"parentId": "level_wyuoxj87czq3v0re",
"visible": true,
"metadata": {},
"polygon": [
[
7,
5
],
[
10,
5
],
[
10,
8
],
[
7,
8
]
],
"color": "#3b82f6"
},
"zone_r9ma8tvsqt9w1zey": {
"object": "node",
"id": "zone_r9ma8tvsqt9w1zey",
"type": "zone",
"name": "bathroom",
"parentId": "level_wyuoxj87czq3v0re",
"visible": true,
"metadata": {},
"polygon": [
[
4,
6
],
[
6,
6
],
[
6,
8
],
[
4,
8
]
],
"color": "#3b82f6"
},
"zone_l189q61kf9ra2m8t": {
"object": "node",
"id": "zone_l189q61kf9ra2m8t",
"type": "zone",
"name": "living-kitchen",
"parentId": "level_wyuoxj87czq3v0re",
"visible": true,
"metadata": {},
"polygon": [
[
0,
0
],
[
10,
0
],
[
10,
5
],
[
7,
5
],
[
7,
8
],
[
6,
8
],
[
6,
6
],
[
4,
6
],
[
4,
8
],
[
3,
8
],
[
3,
5
],
[
0,
5
]
],
"color": "#3b82f6"
},
"door_cjzja4lt8owg88wg": {
"object": "node",
"id": "door_cjzja4lt8owg88wg",
"type": "door",
"parentId": "wall_qv53jm9kvl7k6slf",
"visible": true,
"metadata": {},
"position": [
0.5,
1.05,
0
],
"rotation": [
0,
0,
0
],
"wallId": "wall_qv53jm9kvl7k6slf",
"width": 0.9,
"height": 2.1,
"frameThickness": 0.05,
"frameDepth": 0.07,
"threshold": true,
"thresholdHeight": 0.02,
"hingesSide": "left",
"swingDirection": "inward",
"segments": [
{
"type": "panel",
"heightRatio": 0.4,
"columnRatios": [
1
],
"dividerThickness": 0.03,
"panelDepth": 0.01,
"panelInset": 0.04
},
{
"type": "panel",
"heightRatio": 0.6,
"columnRatios": [
1
],
"dividerThickness": 0.03,
"panelDepth": 0.01,
"panelInset": 0.04
}
],
"handle": true,
"handleHeight": 1.05,
"handleSide": "right",
"contentPadding": [
0.04,
0.04
],
"doorCloser": false,
"panicBar": false,
"panicBarHeight": 1
},
"door_bs7bf0azevq9vd76": {
"object": "node",
"id": "door_bs7bf0azevq9vd76",
"type": "door",
"parentId": "wall_hrfixeusz7zb7x63",
"visible": true,
"metadata": {},
"position": [
0.5,
1.05,
0
],
"rotation": [
0,
0,
0
],
"wallId": "wall_hrfixeusz7zb7x63",
"width": 0.9,
"height": 2.1,
"frameThickness": 0.05,
"frameDepth": 0.07,
"threshold": true,
"thresholdHeight": 0.02,
"hingesSide": "left",
"swingDirection": "inward",
"segments": [
{
"type": "panel",
"heightRatio": 0.4,
"columnRatios": [
1
],
"dividerThickness": 0.03,
"panelDepth": 0.01,
"panelInset": 0.04
},
{
"type": "panel",
"heightRatio": 0.6,
"columnRatios": [
1
],
"dividerThickness": 0.03,
"panelDepth": 0.01,
"panelInset": 0.04
}
],
"handle": true,
"handleHeight": 1.05,
"handleSide": "right",
"contentPadding": [
0.04,
0.04
],
"doorCloser": false,
"panicBar": false,
"panicBarHeight": 1
},
"door_o8etwqsemfgj5mkj": {
"object": "node",
"id": "door_o8etwqsemfgj5mkj",
"type": "door",
"parentId": "wall_1ullk9bm6dw15i9t",
"visible": true,
"metadata": {},
"position": [
0.5,
1.05,
0
],
"rotation": [
0,
0,
0
],
"wallId": "wall_1ullk9bm6dw15i9t",
"width": 0.9,
"height": 2.1,
"frameThickness": 0.05,
"frameDepth": 0.07,
"threshold": true,
"thresholdHeight": 0.02,
"hingesSide": "left",
"swingDirection": "inward",
"segments": [
{
"type": "panel",
"heightRatio": 0.4,
"columnRatios": [
1
],
"dividerThickness": 0.03,
"panelDepth": 0.01,
"panelInset": 0.04
},
{
"type": "panel",
"heightRatio": 0.6,
"columnRatios": [
1
],
"dividerThickness": 0.03,
"panelDepth": 0.01,
"panelInset": 0.04
}
],
"handle": true,
"handleHeight": 1.05,
"handleSide": "right",
"contentPadding": [
0.04,
0.04
],
"doorCloser": false,
"panicBar": false,
"panicBarHeight": 1
},
"window_47x40mtv2l4ca9p4": {
"object": "node",
"id": "window_47x40mtv2l4ca9p4",
"type": "window",
"parentId": "wall_y87bsrljd2245n51",
"visible": true,
"metadata": {},
"position": [
0.3,
0.6,
0
],
"rotation": [
0,
0,
0
],
"wallId": "wall_y87bsrljd2245n51",
"width": 1.2,
"height": 1.2,
"frameThickness": 0.05,
"frameDepth": 0.07,
"columnRatios": [
1
],
"rowRatios": [
1
],
"columnDividerThickness": 0.03,
"rowDividerThickness": 0.03,
"sill": true,
"sillDepth": 0.08,
"sillThickness": 0.03
},
"window_n09awmg5m3ct4fvn": {
"object": "node",
"id": "window_n09awmg5m3ct4fvn",
"type": "window",
"parentId": "wall_y87bsrljd2245n51",
"visible": true,
"metadata": {},
"position": [
0.7,
0.6,
0
],
"rotation": [
0,
0,
0
],
"wallId": "wall_y87bsrljd2245n51",
"width": 1.2,
"height": 1.2,
"frameThickness": 0.05,
"frameDepth": 0.07,
"columnRatios": [
1
],
"rowRatios": [
1
],
"columnDividerThickness": 0.03,
"rowDividerThickness": 0.03,
"sill": true,
"sillDepth": 0.08,
"sillThickness": 0.03
},
"window_xlta3f3f0cnmbti3": {
"object": "node",
"id": "window_xlta3f3f0cnmbti3",
"type": "window",
"parentId": "wall_aegff27krjwgmkmi",
"visible": true,
"metadata": {},
"position": [
0.5,
0.6,
0
],
"rotation": [
0,
0,
0
],
"wallId": "wall_aegff27krjwgmkmi",
"width": 1.2,
"height": 1.2,
"frameThickness": 0.05,
"frameDepth": 0.07,
"columnRatios": [
1
],
"rowRatios": [
1
],
"columnDividerThickness": 0.03,
"rowDividerThickness": 0.03,
"sill": true,
"sillDepth": 0.08,
"sillThickness": 0.03
}
},
"rootNodeIds": [
"site_xs1r72ib2ymzpjus"
],
"collections": {}
}