Repository navigation
fix(api-wiring): resolve frontend/backend contract drift (audit #9851) - #9862
Merged
Merged
Conversation
…bugs (#9851) The entire codebase_analytics router (81 routes under /api/analytics/codebase/*) was silently unmounted: feature_routers.py swallowed two import-time crashes, leaving ~39 frontend calls hitting 404s. Root causes: - ssot_config.codebase_index_embedding_mode declared `int` (default 0) but the only consumer (chromadb_storage.py) calls `.lower()` → AttributeError. Retyped to `str` (default "precompute"), matching the documented "precompute|auto|skip". - scanner.py annotated `progress_callback: callable | None` using the builtin `callable`; PEP-604 unions evaluate eagerly without `from __future__ import annotations`, so `callable | None` raised TypeError at import. Use typing.Callable. Verified: `import api.codebase_analytics` → 84 routes; OpenAPI dump 1984 → 2065 paths; audit unwired 70 → 31. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…9851) api/user_provider_credentials.py (GH#9037) was never registered and could not have imported: it pulled get_current_user_id and get_db_session from auth_middleware, neither of which exists there. Wired it in correctly: - Router prefix /api/user/provider-credentials → /user/provider-credentials (app_factory prepends /api, so the literal prefix double-counted). - Import get_db_session + new get_current_user_id from api.user_management.dependencies (the canonical home; get_db_session already 503s outside multi-user/postgres, so this user-scoped feature is gated there). - Added get_current_user_id: resolves the authenticated user's UUID from id/user_id/sub, 401 for service/internal principals with no real user id. - Registered in core_routers. Mounts /api/user/provider-credentials (POST/GET) + /{provider_name} (DELETE). No frontend consumer yet (GH#9037 UI pending) — wired per "never silently delete; wire it in". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…scriber (#9851) Transcriber routes were registered twice: core_routers mounts api.transcriber.router (prefix "/transcriber" → /api/transcriber/*, the full surface incl. kb), and feature_routers additionally mounted extensions.builtin.transcriber_extension whose combined router carries a full "/api/transcriber" prefix. Since app_factory prepends "/api", the second registration produced a dead, double-prefixed duplicate at /api/api/transcriber/* (14 phantom paths). Removed the feature_routers entry; the core registration is canonical and ungated, so no behavior is lost. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nts (#9851) Two LLC dashboard calls hit non-existent backends. Both are thin reads over existing models/services, so implemented rather than feature-flagged: - GET /api/llc/heartbeat-runs — org-scoped run feed for CompanyDashboard's "recent runs" panel. Mirrors the per-agent list_runs (runs.py) without the agent filter; org isolation via require_org_context. - GET /api/llc/work-items/{id}/activity — per-item audit trail for WorkItemDetail. Resolves the item's company_id then queries the existing LLCActivityLogService with entity filter (entity_type="work_item"). Reuses ActivityLogResponse/Entry from the company-activity route. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…#9851) Several LLC views called non-existent paths and assumed a {data:{...}} axios envelope the api client doesn't use (it returns parsed JSON directly). Aligned with the real backend: - CompanyDashboard: agents/status→agents, approvals/pending→approvals (with company_id), budgets→budget, activity→companies/{id}/activity (page_size); approvals/{id}/approve→/decide {decision:"approved"}; unwrapped array/items. heartbeat-runs now resolves (new backend endpoint). - WorkItemDetail: artifacts→products (reads {products}); activity reads {items} (ActivityLogResponse) — endpoint now exists. - GoalTree: goals/{id}/items→/tasks, returns an array directly. Note: a separate pre-existing defect remains — CompanyDashboard et al. read route.params.companyId on routes that define no such param (no company store), so company context is unresolved. Tracked in the umbrella (#9851) for a focused fix; these path/shape corrections are prerequisites, not regressions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…9851) DevicePairingSettingsPanel called three non-existent routes and assumed an axios {data} envelope. mobile_devices.py is canonical: - loadPairedDevices: GET /api/devices/paired → GET /api/devices ({devices:[...]}). - startPairingFlow: POST /api/devices/pairing/generate-code → GET /api/devices/pair-qr ({challenge_token}); render the token as the QR. - completePairing: removed the dead POST /api/devices/pairing/confirm — pairing completes mobile-side (the device POSTs the scanned token to /api/devices/pair); the desktop confirms by refreshing the device list. No dead button. ApiClient returns parsed JSON directly, so .data dereferences were dropped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Runs scripts/audit_api_wiring.py on PRs touching backend routes or frontend src: builds the app + dumps app.openapi() (authoritative), falling back to static regex mode if the build fails in CI. Non-blocking for now (continue-on-error) since known false positives remain — template-literal paths, bare base-URL strings, websockets (absent from OpenAPI), and LLC views pending a company-context redesign (#9851). Remove continue-on-error to make it a blocking gate once those are cleared. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…on (#9851) Records what was fixed (codebase_analytics mount, user-creds, transcriber dedup, 2 minimal LLC endpoints, LLC + device-pairing frontend), the IDOR caught in review, deferred items (tracked in #9861), and known audit false positives. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
✅ SSOT Configuration Compliance: Passing🎉 No hardcoded values detected that have SSOT config equivalents! |
8 tasks done
Applied Black, isort, and autoflake to match code-quality checks. Triggered by workflow auto-fix-formatting.yml. Co-Authored-By: Paperclip <noreply@paperclip.ing>
Owner
Author
|
✅ Ready to merge Comprehensive API wiring remediation:
CI green. Merging. |
This was referenced Jun 10, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes part of #9851. Follow-ups tracked in #9861.
Thinking Path
The API wiring audit (authoritative, 2055-path OpenAPI dump) found 70 unwired frontend calls + 3 unmounted routers. Root-caused and fixed the real drift; deferred items that need backend implementation or a frontend redesign rather than patching blind. One commit per logical fix.
What Changed
Backend
codebase_analyticsrouter silently unmounted (2 import-chain type bugs:int-typed embedding-mode.lower(), builtincallable | Noneeager eval) → now mounts 81 paths, resolving ~39 dead/api/analytics/codebase/*calls.user_provider_credentialsmounted (was unregistered + importing phantomauth_middlewaredeps); added aget_current_user_idUUID dependency./api/api/transcriber/*dead duplicate).GET /api/llc/heartbeat-runs,GET /api/llc/work-items/{id}/activity(tenant-isolated).Frontend
{data:{...}}envelope.mobile_devices.py(QR-challenge flow); removed the dead confirm POST.CI
.github/workflows/api-wiring.yml(non-blocking until known FPs cleared).Result: unwired 70→19 (14 false positives, 5 deferred → #9861); unmounted 3→2 (both verified-mounted FPs). Full write-up in
WIRING_AUDIT_REPORT.md.Verification
app.openapi()builds: 2055 paths (all changed backend modules import cleanly).test_activity_log+test_work_item— 30 passed./activityendpoint (caught by automated commit review) fixed before merge — tenant scope fromrequire_org_context.gen:typesmust run against a fully-provisioned backend (constrained-env regen was lossy for 77 endpoints; not committed).Model Used
Claude Opus 4.8 (1M context)