Skip to content

bug(slm-frontend): useAutobotApi names 21 main-backend paths the backend does not serve #15536

Description

@mrveiss

Found while building the route-reachability guard for #15236 AC5. Not in that issue's
scope, so filed separately.

The defect

autobot-slm-frontend/src/composables/useAutobotApi.ts builds an axios client with
baseURL: getBackendUrl(), which returns /autobot-api. The deployed nginx template
(autobot-slm-backend/ansible/roles/slm_manager/templates/autobot-slm.conf.j2:404)
proxies /autobot-api/* to the main backend's /api/*.

28 call sites on that client name 21 distinct paths the main backend does not serve.
Measured against the generated main-backend contract
(autobot-frontend/src/types/generated/api.ts, 2195 paths) unioned with the main
backend's WebSocket routes.

Path built Nearest thing the contract does have
/api/users, /api/users/{id} only /api/users/me/preferences; user CRUD is /api/user-management/users/...
/api/npu-workers and 5 sub-paths nothing under /api/npu-workers
/api/mcp/servers and 4 sub-paths nothing under /api/mcp/servers
/api/permissions/rules/{id} nothing
/api/files/write nothing
/api/agents /api/agents/org, /api/agents/status — no bare collection
/api/voice/config nothing
/api/llm-providers/fallback-status nothing
/api/monitoring/system nothing
/api/monitoring/hardware only /api/monitoring/hardware/npu, /gpu, /system
/api/batch/status nothing

Why this is live, not dead code

getUsers() was reached on every mount of UserManagementSettings.vue, inside
loadLegacyUsers(), whose catch swallowed the 404 with the comment
"Legacy API may not be available - not critical". The result was that the view's
currentUser was permanently null, and the self-service password button opened an
empty modal — that half is fixed in #15533. The other call sites have the same shape:
a caller that fails silently or surfaces a generic error.

Acceptance criteria

  • Every path above either names a route the main backend serves, or its caller is
    removed with the reason recorded, or the route is built and the issue that builds
    it is named.
  • No catch {} left swallowing a 404 from these calls without surfacing it.
  • The entries for this file are removed from _KNOWN_UNSERVED in
    repo_tests/slm_frontend_calls_reach_served_routes_test.py in the same commit
    that fixes them — that baseline is exact and shrink-only.
  • Record the measured count before and after.

Refs #15533, #15236, #15198, #15199.

Activity

  1. added
    bugSomething isn't working
    area: api-contractWave 2 · cluster C — Frontend↔backend API contract
    on Sep 2, 2026
  2. mrveiss commented on Sep 2, 2026

    @mrveiss
    OwnerAuthor

    Measured on Dev_new_gui, then deferred — blocked by #15538

    Re-measured before building, with the extractor from the guard this issue's baseline lives in.

    Measured vs claimed

    Claim Measured Verdict
    28 call sites in useAutobotApi.ts 28 correct
    21 distinct main-backend paths 21 correct
    main contract = 2195 paths 2196 +1, drift since filing
    the debt is pinned in a shrink-only _KNOWN_UNSERVED baseline the baseline does not exist on Dev_new_gui refuted

    The other 30-site total the sweep reports on this tree is 28 here, plus
    UserManagementSettings.vue:141 (#15533) and TerminalTool.vue:180 (#15236/#15230).
    Resolved population: 127 call sites, 309 SLM routes, 2196 main routes.

    Why this is blocked, not merely large

    repo_tests/slm_frontend_calls_reach_served_routes_test.py is not on Dev_new_gui. It
    is on the unmerged PR #15538. Its test_the_known_unserved_baseline_is_exact fails in both
    directions, so any call fixed from this base leaves a stale entry behind and reddens #15538
    the moment it lands. Dev_new_gui has required_status_checks.strict = false, so a stale
    #15538 can merge without a rebase and take the base branch red with it.

    #15538 also edits autobot-slm-frontend/src/views/settings/admin/UserManagementSettings.vue,
    which is the only external caller of the getUsers() half of this issue. So the collision is
    at file level as well as at baseline level.

    Order of operations: merge #15538, then rebase, then fix this issue and lower the pin in the
    same commit
    — which is what this issue's third acceptance criterion asks for and which is
    only possible after #15538 lands.

    Per-call verdict — caller goes, or route should exist

    Nearest served route taken from the generated main contract. Where a route is named, the fix
    is to re-point the caller; where none is, the backend half was never built and that half is a
    separate issue rather than a contract to invent here.

    Path called Sites Verdict Nearest served route
    /api/users 2 re-point /api/user-management/users
    /api/users/{id} 2 re-point /api/user-management/users/{user_id}
    /api/npu-workers 1 re-point /api/npu/workers
    /api/npu-workers/{id} 3 re-point /api/npu/workers/{worker_id}
    /api/npu-workers/load-balancing/config 2 re-point /api/npu/load-balancing
    /api/npu-workers/{id}/pair 1 re-point (shape differs: no id in path) /api/npu/workers/pair
    /api/npu-workers/{id}/restart 1 route should exist none; /api/npu/workers/{worker_id}/logging is the only sub-route
    /api/npu-workers/{id}/test 1 route should exist none
    /api/mcp/servers and 4 sub-paths 5 route should exist none; /api/mcp/ serves bridges, tokens and tools, never a server registry
    /api/permissions/rules/{id} 2 route should exist /api/permissions/rules is a collection only — no item route for PATCH or DELETE
    /api/files/write 1 needs a decision /api/files/upload exists; whether write is upload is not answerable from the code
    /api/agents 1 re-point /api/agent_config/agents (or /api/agent/agents/status)
    /api/voice/config 2 route should exist none; the voice surface has 14 routes and no config
    /api/llm-providers/fallback-status 1 route should exist none; there is no /api/llm-providers/* at all
    /api/monitoring/system 1 re-point /api/monitoring/hardware/system
    /api/monitoring/hardware 1 re-point /api/monitoring/hardware/{system,gpu,npu} — the caller must pick
    /api/batch/status 1 re-point /api/batch-jobs/status — the neighbouring getBatchJobsHealth in the same file was already re-pointed this way under #10429

    12 sites re-point, 14 wait on a backend half, 1 needs a product decision, 1 (/api/files/write)
    is the same. Verbs still need confirming per site against the contract; that is part of the
    work, not part of this measurement.

    Note also that 18 of the 28 call sites have no caller anywhere in the SLM frontend
    (getMCPServers, startMCPServer, stopMCPServer, restartMCPServer, getMCPServer,
    getAgents, getVoiceConfig, updateVoiceConfig, getSystemMetrics, getHardwareInfo,
    getBatchStatus, writeFile, updatePermissionRule, deletePermissionRule, getNPUWorker)
    — they are unwired composable methods, not live buttons. The live ones are getUsers,
    createUser, updateUser, deleteUser, the NPU worker set and getLLMFallbackStatus.

    Blocked by #15538. Delivered separately from this branch: #15527 in PR #15541.

  3. modified the milestones: Backlog, v0.14.0 on Sep 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: api-contractWave 2 · cluster C — Frontend↔backend API contractbugSomething isn't workingfrontend

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions