Quote-safe multi-token outfmt to shard pods (UNQUOTED wire format)¶
Motivation¶
To surface subject taxids/names, the BLAST search needs a multi-token tabular
outfmt, e.g. -outfmt 7 sseqid staxids sstrand pident evalue bitscore .... Two
hot-path mechanisms broke a multi-token specifier on the way to each shard pod:
- YAML injection — elastic-blast injects
ELB_BLAST_OPTIONSinto the job YAML viasubstitute_params, a raw${VAR}regex replace with NO YAML escaping (value: "${ELB_BLAST_OPTIONS}"). A quoted value (-outfmt "7 ...") closes the YAML scalar early → broken manifest. - Shell word-splitting —
blast-run-aks.shexpands$ELB_BLAST_OPTIONSUNQUOTED (SC2086 disabled on purpose), so-outfmt "7 ..."(or an unquoted-outfmt 7 std staxids) splits into stray positional args forblastn.
The fix is a single canonical wire format that needs no quotes at all:
UNQUOTED multi-token outfmt in the ini/env, with each consumer rejoining the
-outfmt tokens. Quotes are never introduced, so the YAML injection stays valid
and there is no eval/escaping anywhere.
Correction to the prior change note
2026-06-10-outfmt7-extended-taxids-guard.md: that note recommended passing the specifier QUOTED viaadditional_options. That is wrong for the YAML path (raw substitution breaks on the quote). The canonical format is UNQUOTED; the rejoin in the merge + run script recovers the full specifier.
Scope (gates still CLOSED — not reachable from a production submit)¶
The FE / backend / elastic-blast merge gates still admit only
5/6/6 std…/7/7 std…, so a reordered/extended specifier cannot reach these
paths from a production submit. The run-script patch is byte-identical for the
single-token -outfmt every current job uses, so rebuilding the terminal /
OpenAPI image is safe for existing runs; the multi-token path is exercised only
by isolated tests until the gates open AND a non-prod live run confirms the
end-to-end YAML→env→shell→blastn flow.
API / IaC diff summary¶
terminal/merge-sharded-results.shparse_outfmt_spec(): rejoin every token after-outfmtup to the next-flag, so the full specifier is recovered from the UNQUOTED wire format (previously it took only the single token right after-outfmt, which silently dropped the extended fields).terminal/patch_elastic_blast.pynewpatch_blast_run_aks_outfmt_argv(wired intopatch_blast_run_aks_script): rebuildsELB_BLAST_OPTIONSinto a quote-safeELB_BLAST_ARGVarray, rejoining a multi-token-outfmtinto one element, and swaps theblastninvocation to"${ELB_BLAST_ARGV[@]}". Noeval, no quotes. Byte-identical for single-token-outfmt. Skips gracefully when the anchor is absent; raises if the anchor is present but the invocation line drifted. No YAML template change is needed (unquoted ⇒ valid YAML).
Validation evidence¶
api/tests/test_terminal_patch_elastic_blast.py(runs the patched stub in bash): single-token-outfmt 5→ argv byte-identical to plain word-splitting; multi-token-outfmt 7 sseqid staxids …→ ONE grouped argv element;-outfmtat end grouped; patch idempotent.api/tests/test_sharded_merge.py::…_unquoted_multitoken— the merge resolves the full specifier from the UNQUOTED form.- Full
patch_elastic_blast.pyapplied to a copy of the REAL sibling tree: no crash, the argv rebuild +"${ELB_BLAST_ARGV[@]}"land exactly once. uv run pytest -q api/tests -m '' -k "shard or merge or sharding or precision or terminal_patch or web_blast or parity"— 257 passed, 3 skipped.uv run ruff check …— passed; embedded merge pythonast.parseclean.
Remaining for end-to-end (gates still closed)¶
- Dashboard: normalise the submitted outfmt to lead with
qseqid(the merge + read-side aggregation key on it) and emit the multi-token specifier UNQUOTED. - Open the FE/backend/elastic-blast gates to
7 <arbitrary fields>. - Live-verify on a NON-PRODUCTION cluster (the YAML→env→shell→blastn quoting is the one link that cannot be unit-tested) before any production image rebuild.