Fix broken result-download fallback (removed SAS download_url path)¶
Motivation¶
While validating the Service Bus outfmt-7 queue path (20 parallel jobs), the
BLAST result download code revealed a latent broken fallback. The result
download button (useBlastResultActions.handleDownload) had two branches:
file.file_idpresent →blastApi.downloadResultFile→GET /results/{file_id}which streams the bytes through the api sidecar. This is the working path (verified live: 200 on every job).else→blastApi.downloadResult→GET /results/download?blob_name=…thenwindow.open(resp.download_url).
The else branch was stale: the /results/download endpoint was changed to
stream bytes through the sidecar (charter §9 — no SAS URL is ever handed to the
browser), but the frontend still treated the response as JSON { download_url }
and called window.open(undefined). It additionally passed file.name (a
basename) as blob_name, which the per-job blob guard rejects. The branch could
never succeed.
It was unreachable in practice — every result file from the listing carries a
file_id (local blobs get a deterministic base64 encoding via
encode_blob_file_id; external OpenAPI / Service Bus jobs keep their
sibling-generated result-NNN id) — but it was dead, broken code on the
download path.
User-facing change¶
- The result download button now always uses the streaming
file_idpath. A malformed listing entry without afile_idsurfaces a clear error toast instead of silently openingundefined. - No change for the normal case: downloads already worked via the
file_idpath; this removes the broken fallback and its misleading API method.
API / IaC diff summary¶
web/src/hooks/useBlastResultActions.ts:handleDownloaddrops thedownload_url/window.openfallback; guards a missingfile_idwith a toast and otherwise streams viadownloadResultFile.web/src/api/blast.ts: removed the unuseddownloadResultmethod (the only caller was the deleted fallback) and its stale{ download_url: string }return type.- Backend unchanged: the
GET /jobs/{job_id}/results/downloadroute (and its path-traversal / cross-job security guards + contract test) is left intact for direct API consumers; it is simply no longer called by the SPA.
Validation evidence¶
npm run build(web) — clean.npx eslint web/src/hooks/useBlastResultActions.ts web/src/api/blast.ts— clean.npx vitest run src/pages/blastResultsModel.test.ts src/hooks— 70 passed.- Live: result downloads via
GET /results/{file_id}returned 200 on 6/6 spot-checked Service Bus outfmt-7 jobs; the removed branch was never the path exercised by the UI.