# Update Layout

Use this when fields already exist and the task is only about form grouping or ordering.

## Minimal sequence

1. `app_get_fields`
2. `app_get_layout`
3. `builder_tool_contract` when the section shape is not already obvious
4. `app_layout_apply`

## Example

Apply a custom layout with the canonical public section shape:

```json
{
  "tool_name": "app_layout_apply",
  "arguments": {
    "profile": "default",
    "app_key": "APP_123",
    "mode": "merge",
    "publish": true,
    "sections": [
      {
        "title": "基础信息",
        "rows": [
          ["客户名称", "订单金额"],
          ["状态", "跟进日期"]
        ]
      }
    ]
  }
}
```

## Common failures

### `UNKNOWN_LAYOUT_FIELD`

At least one field name does not exist. Re-read with `app_get_fields`.

### `DUPLICATE_LAYOUT_FIELD`

The same field appears more than once in the requested layout.

### `INCOMPLETE_LAYOUT`

Only happens in `mode=replace`. Switch to `mode=merge` unless you intend to place every field exactly once.

### `LAYOUT_APPLY_FAILED`

Re-read with `app_get_layout`. Check `current_field_names`, `request_id`, and `suggested_next_call`.

### `VALIDATION_ERROR`

Do not keep guessing section keys. Reuse `suggested_next_call`, `canonical_arguments`, `section_allowed_keys`, and `minimal_section_example`.

If the same shape error repeats twice, stop free-form retries and re-read `builder_tool_contract(app_layout_apply)`.

## Notes

- `section_id` is optional; it is generated from the section title
- `merge` is safer than `replace`
- Unmentioned fields stay in place or get auto-added to `未分组字段`
- Public builder layout sections use `title + rows`
- Do not treat “一行四个字段 / 四列布局 / 每行放四个” as a top-level `columns` parameter; translate it into a `rows` matrix
- Do not prefer `fields` or `field_ids` once `rows` is known, even though MCP may normalize those shorthands for recovery
