feat(aws-healthomics): document WDL engine selection, silent incompatibilities, and how to read lint results - #179
Conversation
|
Re-verified the lint behavior against the current Still |
cb0d398 to
fdccbf3
Compare
…patibilities The CreateAHOWorkflow schema describes WDL_LENIENT as useful "when migrating legacy workflows designed to run on Cromwell", but the Cromwell WDL migration SOP never mentions engine choice. Add it to Phase 3 with two boundaries measured against the service: leniency applies to registration-time syntax rather than runtime type coercion, so a lossy String-to-Int conversion registers ACTIVE under both engines and fails identically once the task runs; and a definition with no version declaration registers ACTIVE under both engines with draft-2 assumed, so neither engine substitutes for declaring the version. Add a Silent Incompatibilities section for Cromwell habits that survive every gate here. Three of them are directives whose HealthOmics meaning differs from their Cromwell meaning, quoted from the service documentation: preemptible controls 5XX retry behavior and has no spot-capacity meaning; disks contributes only a size, summed into one /tmp allocation, and is ignored entirely for CPU tasks in the default SHARED scratch storage mode; maxRetries needs GNU findutils 4.2.3+ in the image or a task that declares retries does not get them. The rest: outputs written outside the task working directory, String used to pass a directory of files, thread counts not tied to the cpu request, unbounded scatter, GB where the task was tuned in GiB, and absolute or remote imports. Phase 2 no longer lists disks alongside cpu and memory, since a missing disks is not a defect. Also record how to read Lint* results: the tools return "status": "success" for a definition that fails to parse, so an agent branching on status alone passes broken files.
fdccbf3 to
26ee412
Compare
|
Updated: the three runtime directives I had originally left out —
Two things I corrected in the process, in case they affect how you read the rest:
Also adjusted Phase 2 step 2, which listed |
markjschreiber
left a comment
There was a problem hiding this comment.
Some great updates! Thanks
What
Two additions to the WDL migration SOP, plus a note on reading lint results:
WDL_LENIENT, even though theCreateAHOWorkflowschema describes it as the option for migrating Cromwell workflows — which is exactly this SOP's subject. Added to Phase 3, together with the limits of what it buys.## Silent Incompatibilities. Defects that produce no error: the run reaches COMPLETED and the result means something other than what the author intended. No gate in this SOP catches them.LintAHOWorkflowDefinitionreturns"status": "success"for a file that fails to parse. The real verdict isReturn code:insideraw_output.Mostly additive. The only edited lines are Phase 3's step numbering and Done WHEN, plus two bullets in
workflow-development.md's Linting section.1.
WDL_LENIENTis missing from the Cromwell migration SOPmigration-guide-for-wdl.md:14covers WDL versions but not engine choice:Meanwhile the
CreateAHOWorkflowtool schema says of itsengineparameter:A bridge documented as being for Cromwell migration is absent from the Cromwell migration SOP. An agent following this SOP will register under
WDLand may rewrite directives that did not need rewriting.But introducing it alone would create a new misconception — that lenient gets legacy workflows through. It does not, and I measured the boundary. Identical bytes, identical parameters, engine as the only variable:
WDLACTIVEcoercing String to Int: invalid literal for int() with base 10: '3.7'WDL_LENIENTACTIVEcannot coerce String '3.7' to Int: value has a fractional part(workflows
6243482/5645495; runs2968222/4945591)Different wording, same outcome.
WDL_LENIENT's leniency is about registration-time syntax, not runtime type coercion — and note that both engines registered the lossy conversion asACTIVE. Engine selection is not the gate that catches it; nothing does until a task runs.A related probe, run today in
us-west-2while preparing this PR: a definition with noversiondeclaration registersACTIVEunder both engines, notFAILED.Same result under
WDL(workflow3334792). Somigration-guide-for-wdl.md:14's "draft-2 is NOT supported" does not mean rejected at creation — the service assumes draft-2 and records it as a warning on anACTIVEworkflow. I have left line 14 alone, since I do not know whether "not supported" is meant as unvalidated-and-unrecommended. But it is why step 4 says neither engine substitutes for declaring the version, rather than claiming lenient rejects draft-2 (an earlier draft of this PR did claim that, and it is wrong).So Phase 3 step 4 introduces the option and states both limits in the same breath.
2.
## Silent IncompatibilitiesThe existing Phases fail loudly or not at all. This section collects the cases that pass everything and change the meaning of the result. Nine items, each with a Before/After, a detection rule, or the service's own wording:
samtools sort -o /data/out.bam— the task exits 0 and the file is discarded. Data loss, not failure. Distinct from Phase 5, which covers outputs that were never declared; here it is declared and written somewhere that is not collected.Stringused to pass a directory of files. OnlyFile/Directoryvalues are localized. AStringis opaque text, so nothing is staged. Classic Cromwell-ism from shared-filesystem days. What makes it expensive to debug is that the error names a file the author never mentioned — a.bwtindex — several lines from the declaration that caused it.Int threads = 16withruntime { cpu: 4 }. A literal in a flag is visible on review; a literal in a declaration referenced as-t ~{threads}is not.scatter. Cromwell deployments were bounded by a cluster queue; there is no equivalent here. Points at run groups, with--max-durationlabelled as minutes — the flag takes minutes and that is easy to misread as hours.GBwhere the task was tuned inGiB. Both forms parse and run; they differ by 7.4%, enough to move a borderline task into an OOM kill. A barememory: 8is a different bug (it does not reach COMPLETED) so it is pointed back at the Phase 2 audit rather than described here.import "/home/shared/wdl/tasks/align.wdl"resolves on the origin cluster and is not in the zip; anhttp(s)://import is not fetched. Phase 3 step 3 checks import versions, aliasing and cycles — not whether the path exists in the package. On-prem definitions almost always carry at least one. This item is flagged in the text as failing rather than passing silently, since it surfaces as a registrationFAILEDat a distance from its cause.Three of the nine are quoted directly from the AWS docs rather than described in my own words, because they are directives whose HealthOmics meaning differs from their Cromwell meaning and I would rather the SOP carry the service's own wording:
preemptible— in HealthOmics this controls 5XX retry behavior and has no spot/discounted-capacity meaning at all. The documented values are0(opt out),1, and2(retry limit,2being the default). So a Cromwellpreemptible: 2— two attempts on preemptible VMs — silently becomes a no-op that still reads like a cost control. (WDL support, "Configure task retry for service errors")disks— "The mount path and disk type specifier (SSD,HDD) are ignored — only the numeric size is extracted. If multiple entries are declared, the sizes are summed into a single/tmpallocation." So a scratch layout split across named volumes does not survive migration. Whether the size is used at all depends onscratchStorageMode: in the defaultSHAREDmodedisksis ignored entirely for CPU tasks; underLOCALit is honored as a hint rounded up to 16 GiB. (WDL support, "Supported WDLdisksforms"; ephemeral storage)maxRetries— retries OOM failures with memory doubling, and "requires GNU findutils 4.2.3+" in the image. A task that declares retries but sits on an image without the package is indistinguishable from one that retried and failed again, so the section gives afind --versioncheck rather than guessing at which base images carry it. (WDL support, "Configure task retry for out of memory")The
disksfinding is also why I touched Phase 2 step 2. It currently readsIdentify tasks missing cpu, memory, or disks attributes, which putsdisksalongside two genuinely required attributes; a missingdisksis not a defect. I changed it to notediskswithout flagging its absence, and pointed at the new section. I did not touch the three added doc links in## References' neighbours or anything else in Phase 2.On evidence generally: the engine comparison, the
MissingVersionprobes, and the lint behavior are mine, measured. The other six items in the new section come from porting Cromwell WDL plus the WDL/HealthOmics docs, and each is stated as a rule rather than as a measurement. Two corrections I made to my own earlier draft, in case they matter to your reading of the rest:--max-durationis minutes (checked againstaws omics create-run-group help), and I removed a claim that these workflows have no internet access, sincevpc-connected-workflow-runs.mdin this same Power says otherwise — the real constraint on imports is that they resolve from the zip package, not from the network. Happy to cut any item you would rather not assert.3. Reading lint results
workflow-development.md:88-91says to call theLint*tools and not deploy if errors exist, but not how to tell. Measured:"status": "success"means the linter ran, not that the workflow is valid. An agent that branches onstatuscalls a parse failure a pass. The verdict isReturn code:inraw_output.This is the same envelope-vs-verdict shape as
CreateWorkflowreturning 200 +CREATINGfor a definition that later goesFAILED(that one is #177).I also added a line noting that a clean lint means the definition parses — it is not evidence of semantic correctness — linking to the new Silent Incompatibilities section. Every item in that section lints clean.
Scope
migration-guide-for-wdl.md— Phase 2 step 2 (disksno longer listed as a required attribute), Phase 3 (engine selection, lint verdict, renumbering of the old step 4), the new## Silent Incompatibilitiessection, a cross-reference from## WDL-Specific Considerations, and three doc links in## References. Plus two bullets inworkflow-development.md's Linting section.Not changed: the Nextflow guide, container/ECR guidance, resource limit values, and
migration-guide-for-wdl.md:14("draft-2 is NOT supported") — see the note above on why I left that one to you.Independent of my #177 and #178 — no overlapping hunks, any merge order works. If this is too much for one PR, the natural split is engine-selection + lint (small, measured) from the Silent Incompatibilities section (larger, doc-derived); say the word and I'll split it.
Measurement conditions
The engine comparison: 2026-07,
ap-northeast-2, two accounts (one with no pre-existing HealthOmics resources), miniwdl 1.15.0 / Python 3.12.13. TheMissingVersionprobes (3334792,8405254) and the lint re-check: 2026-08-04,us-west-2, againstawslabs.aws-healthomics-mcp-server@latest. Run and workflow IDs are left unmasked as they are meaningless without the account ID.