The MCP server covered the logical canvas only. A client could create a
design whose design_type is `rack` and then had no way to put a rack, a
mount or a cable in it, and it could triage the Device Inventory but
never create, edit or delete an entry — though every route already
existed. 24 tools become 47.
Racks (mcp/app/racks.py), 13 tools: list_racks, get_rack,
list_rack_inventory, list_faceplates, create_rack, update_rack,
delete_rack, mount_device, mount_accessory, unmount_device, move_device,
set_device_faceplate, patch_cable, unpatch_cable.
`POST /api/v1/racks/save` is full-state upsert-and-prune, so every write
is load, mutate, save it all back. Two traps are encoded once, in the
helpers: the response rows carry `design_id` and the save schemas do not
(echoing one back verbatim is a 422), and the viewport has to be echoed
or the save resets the user's pan and zoom. The plate, its colour and its
ports need no special handling — /racks/save writes those through to the
inventory row itself.
Two frontend files are copied rather than imported, since the MCP server
is a separate service:
- mcp/app/faceplates.py — the 21-plate catalog from
frontend/src/rack/faceplates.ts, data only. `bank()` reproduces the
port arithmetic exactly, so a plate seeded here lands its ports where
the renderer draws them.
- mcp/app/rack_layout.py — canPlace / findSlot / freeUnits from
frontend/src/rack/layout.ts, to *choose* a slot. The backend still
polices the one it is sent.
Both are guarded against drift: test_faceplates_sync.py parses
faceplates.ts and compares every plate down to each port's coordinates,
the way test_node_types_sync.py guards NODE_TYPES, and
test_layout_parity.py runs the frontend's own layout cases against the
Python port.
Devices (mcp/app/devices.py), 10 tools: create_device, update_device,
delete_device, bulk_approve_devices, bulk_hide_devices,
bulk_restore_devices, rescan_device, list_proxmox_children,
get_scan_config, update_scan_config.
Verified against a running backend: the rack flow end to end (create,
mount, patch, move, swap a plate, shrink, unmount) plus every refusal
path, and the device tools including a byte-identical scan-config
write-back.
ha-relevant: no
83 lines
2.2 KiB
YAML
83 lines
2.2 KiB
YAML
name: Quality
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
pull_request:
|
|
branches: [main]
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
lint-scripts:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- name: ShellCheck — lxc-install.sh
|
|
uses: ludeeus/action-shellcheck@2.0.0
|
|
with:
|
|
scandir: './scripts'
|
|
- name: Hadolint — Dockerfile.backend
|
|
uses: hadolint/hadolint-action@v3.1.0
|
|
with:
|
|
dockerfile: Dockerfile.backend
|
|
ignore: DL3008
|
|
- name: Hadolint — Dockerfile.frontend
|
|
uses: hadolint/hadolint-action@v3.1.0
|
|
with:
|
|
dockerfile: Dockerfile.frontend
|
|
ignore: DL3008
|
|
|
|
frontend:
|
|
runs-on: ubuntu-latest
|
|
defaults:
|
|
run:
|
|
working-directory: frontend
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '20'
|
|
cache: 'npm'
|
|
cache-dependency-path: frontend/package-lock.json
|
|
- run: npm ci
|
|
- run: npm run lint
|
|
- run: npm run typecheck
|
|
- run: npm test -- --run
|
|
|
|
backend:
|
|
runs-on: ubuntu-latest
|
|
defaults:
|
|
run:
|
|
working-directory: backend
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.11'
|
|
- run: pip install -r requirements.txt
|
|
- run: ruff check .
|
|
- run: mypy app/
|
|
- run: pytest
|
|
|
|
# Also guards the copies the MCP server keeps of frontend data against drift:
|
|
# NODE_TYPES / EDGE_TYPES in mcp/app/tools.py against frontend/src/types/index.ts,
|
|
# and the faceplate catalog in mcp/app/faceplates.py against
|
|
# frontend/src/rack/faceplates.ts (test_node_types_sync.py,
|
|
# test_edge_types_sync.py, test_faceplates_sync.py) — those tests need the
|
|
# frontend sources, so this job runs from a full checkout rather than the mcp
|
|
# Docker context.
|
|
mcp:
|
|
runs-on: ubuntu-latest
|
|
defaults:
|
|
run:
|
|
working-directory: mcp
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.13'
|
|
- run: pip install -r requirements.txt
|
|
- run: pytest
|