OpenAPI BLAST Contract Hardening¶
Motivation¶
The external OpenAPI facade for BLAST submit, status, and result downloads was functional, but several contracts were implicit or upstream-shaped. External callers need stable submit correlation, explicit public status values, validated inline FASTA, and result file metadata that can be used without knowing dashboard-internal Storage blob paths.
Fifty-Point Critique¶
- Submit returned upstream status strings without a stable public vocabulary.
- Status returned
completedfrom some upstreams even though the public facade documentssuccess. - Failed variants such as
failure,error, andtimeoutwere not normalized. - Running variants such as
submitted,submitting, andfinalizingleaked implementation phases. - Queued variants such as
acceptedandpendingwere not collapsed toqueued. - Submit did not guarantee
submission_sourcein the response when upstream omitted it. - Submit ignored caller-provided
external_correlation_ideven though the public example documents it. - The trusted
submission_sourceguard was correct but undocumented in response shaping. - Direct external callers could not reliably join their own correlation id to later status records.
/api/blast/jobsinline FASTA submit and/api/v1/elastic-blast/submitcould diverge in response shape.- Inline FASTA was only hashed for metadata and invalid FASTA could reach the sibling service.
- Sequence data before the first FASTA header was not rejected at the facade boundary.
- Empty FASTA records were not rejected at the facade boundary.
- Duplicate FASTA query ids were not rejected at the facade boundary.
is_inclusive=truewithouttaxidproduced an ambiguous taxonomy request.taxidwithoutis_inclusiveleft inclusion semantics implicit.outfmtwas correctly fixed to XML, but status/result routes did not reinforce XML result expectations.- Result file entries could expose
namebut notfilename. - Result file entries could expose
sizebut notsize_bytes. - Result file entries could omit
format, making parseability ambiguous. - Result file entries could omit
file_id, breaking the documented file download path. - The manifest and status result shapes were not aligned.
- Local and external result file metadata used different alias sets.
- Manifest schema version stayed stable but did not expose compatibility aliases.
- The facade did not guarantee
db_namewhen upstream returned onlydb. - The facade did not guarantee
programwhen upstream omitted it on submit response. - The facade did not reserve
blast_versionanddb_versionkeys when upstream had not filled them yet. - Submit accepted async work but did not make the accepted-vs-complete distinction obvious in every response.
- The cURL example used a string priority while the schema requires an integer.
- The status route was a raw proxy instead of a contract boundary.
- The submit route was a raw proxy instead of a contract boundary.
- The canonical dashboard job submit wrapper repeated external response shaping logic.
- Correlation metadata could differ between the two submit entry points.
- Public response fields depended on the exact sibling service version.
- Older sibling responses with
name/sizefile fields were less client-friendly. - Newer sibling responses with
filename/size_byteswere not projected into dashboard-style manifests. - Clients had to branch between result manifest and status result file shapes.
- Tests covered non-XML
outfmtrejection but not invalid FASTA rejection. - Tests covered taxonomy pass-through but not inclusive defaulting.
- Tests covered status forwarding but not public status normalization.
- Tests covered manifest parseability but not alias compatibility fields.
- The external facade could not prove it preserved caller correlation after submit.
- Upstream
result.files[]normalization was not tested. - Documentation and API behavior drifted on
external_correlation_id. - Documentation and API behavior drifted on
prioritytype. - Status responses could be less reproducibility-friendly when version keys were absent.
- Unknown status strings fell through without a documented default.
- The result file contract depended too much on upstream naming conventions.
- The facade did not fail early for taxonomy combinations that have no effect.
- The public API was correct in pieces, but too much of the contract lived in convention rather than code.
User-Facing Change¶
- External submit preserves a valid caller
external_correlation_idwhile keepingsubmission_sourceserver-derived asexternal_api. - External submit rejects malformed inline FASTA before contacting the sibling OpenAPI service.
taxidnow defaultsis_inclusivetotrue;is_inclusivewithouttaxidis rejected.- Submit/status responses normalize status to
queued,running,success, orfailed. - Result file entries returned by status and manifest include both
filename/nameandsize_bytes/sizealiases. - The API Reference example now uses numeric
priority.
API/IaC Diff Summary¶
- API only. No infrastructure changes.
- Updated
/api/v1/elastic-blast/submit,/api/v1/elastic-blast/jobs/{job_id}, and/api/blast/jobsinline FASTA response shaping. - Updated result manifest helper to include file metadata aliases.
Validation Evidence¶
uv run pytest -q api/tests/test_external_blast_api.py api/tests/test_blast_result_manifest.py→ 49 passed.uv run pytest -q api/tests/test_route_contracts.py api/tests/test_smoke.py→ 83 passed.uv run ruff check api/routes/elastic_blast.py api/routes/blast/submit.py api/services/blast/result_manifest.py api/main.py→ passed.uv run ruff format --check api/routes/elastic_blast.py api/routes/blast/submit.py api/services/blast/result_manifest.py api/main.py→ already formatted.uv run pytest -q api/testswas also run for signal and reached 1434 passed / 2 failed. The failures were outside this change:api/tests/test_response_contracts.py::test_preflight_returns_admission_decisioncurrently depends on unmocked BLAST database availability, andapi/tests/test_terminal_exec.py::test_run_truncates_stdout_above_captimed out in the local exec-server large-output stub.