fix(workflows): validate honors method args set in model definition (swamp-club#359)#1392
Conversation
…swamp-club#359) `swamp workflow validate` was reporting `Missing required inputs: <arg>` for `model_method` steps whose required method argument was supplied by the model definition's `methods.<method>.arguments` (or `globalArguments`) instead of the step's `inputs:` block. The check (#8) inspected only the step inputs and ignored definition-supplied arguments, even though the runtime executor merges them as fallbacks. The workflows ran successfully — only validate was wrong. Enrich the `MethodResolution` value type with an optional `definitionProvidedArgs` field, populate it in `createModelMethodResolver` from the resolved `Definition`, and union it with step inputs when computing the missing-arg set. The runtime merge in `DefaultMethodExecutionService` is the reference behavior the validator now mirrors. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
CLI UX Review
Blocking
None.
Suggestions
None.
Verdict
PASS — This PR is a pure internal bug fix. No flags, help text, renderers, output shapes, or JSON structures were changed. The only user-visible effect is the correct behavior: swamp workflow validate no longer emits a false Missing required inputs: <arg> error when the argument is already supplied by the model definition, making validate consistent with run. Error message format, exit codes, and both log/json output modes are unaffected.
There was a problem hiding this comment.
Code Review
Blocking Issues
None.
Suggestions
None — this is a clean, well-scoped fix.
Summary: The PR correctly fixes the false-positive Missing required inputs error in swamp workflow validate by enriching MethodResolution with definitionProvidedArgs and unioning them with step-level inputs when computing the missing-arg set. The approach mirrors the runtime merge in DefaultMethodExecutionService.execute.
What I checked:
- DDD conformance:
MethodResolutionis a domain value type enriched with an optional field. The resolver port stays in the domain; the infrastructure populates it increateModelMethodResolver. Clean separation. - Libswamp import boundary:
validate.tsis libswamp-internal code importing from domain paths — allowed.MethodResolutionis not re-exported frommod.ts(correctly, since it's an internal contract between the domain service and its port implementation). - Runtime parity: Verified the resolver populates
definitionProvidedArgsfrom the same sources (definition.getMethodArguments(method)+definition.globalArguments) thatDefaultMethodExecutionService.executemerges at runtime (lines 245–257 ofmethod_execution_service.ts). - Backward compatibility: The
definitionProvidedArgs?: string[]field is optional with?? []fallback — existingMethodResolutionconstructions (e.g., pre-existing tests that omit the field) continue to work unchanged, confirmed by the dedicated backward-compat test. - Test coverage: 5 new unit tests cover all key scenarios: definition supplies all args, partial split with step inputs, partial unsatisfied (error names only the truly-missing key), overlap, and legacy mock backward compat.
- Code style: License headers present, named exports, no
anytypes, test naming followsfunctionName: describes behaviorconvention. - Security: No concerns — no user input handling, no new external calls.
There was a problem hiding this comment.
Adversarial Review
Critical / High
None.
Medium
None.
Low
-
Validator/runtime asymmetry on expression-filtered global args —
src/libswamp/workflows/validate.ts:129-134The runtime (
DefaultMethodExecutionService.executeatmethod_execution_service.ts:266-271) filters out global arguments whose values contain${{ ... }}expressions before merging them into method args. The validator counts all global arg keys as "provided" regardless of whether their values are unresolved expressions.Breaking scenario: A model definition has
globalArguments: { run: "${{ workflow.input.command }}" }and the method requiresrun. The workflow step supplies no step-levelruninput. The validator seesrunas a key inglobalArgumentsand passes. At runtime,runis filtered from the merge because it contains an unresolved expression, causing Zod schema validation to fail.Mitigating factors: (a) The PR comment at line 126–127 explicitly documents this as intentional ("invalid CEL is a runtime concern, not a validator concern"). (b) The unresolved expression is still accessible via the
context.globalArgsProxy at runtime, so the intent is for it to be provided. (c) This only affects global args with expressions — method-specific args with expressions are included in the runtime merge and are consistent with the validator.Verdict on this finding: Documented design choice, not a bug. The validator's purpose is "did the user forget to wire this argument?" not "will the expression resolve?" — so this behavior is defensible.
-
definitionProvidedArgsalways populated even when empty —src/libswamp/workflows/validate.ts:129-134When neither
getMethodArguments(methodName)norglobalArgumentshave any keys,definitionProvidedArgsis set to[]. This is harmless — the?? []fallback in the consumer (validation_service.ts:454) handlesundefined, and[]spreads into an empty set — but it means the field is always present on newly-created resolutions, making the?on the type (definitionProvidedArgs?: string[]) slightly misleading. Not worth changing; the optional type correctly models backward compatibility with existing code that constructsMethodResolutionwithout the field.
Verdict
PASS — The fix is correct and well-scoped. It accurately mirrors the runtime's merge of definition-provided arguments (method + global) into the set of "provided" inputs during validation. The type change is backward-compatible via the optional field with ?? [] fallback. Test coverage is thorough across five scenarios (definition-only, split, partial-miss, overlap, legacy compat). The one asymmetry with expression filtering is documented and intentional.
Summary
swamp workflow validatefalsely reportedMissing required inputs: <arg>formodel_methodsteps whose argument was supplied by the model definition (methods.<method>.argumentsorglobalArguments) instead of the step'sinputs:block.inputs:and ignored definition-supplied args, even though the runtime executor merges them as fallbacks — workflows ran fine; onlyvalidatewas wrong.Approach
MethodResolution(resolved variant) with an optionaldefinitionProvidedArgs: string[].createModelMethodResolverpopulates it fromdefinition.getMethodArguments(method)∪definition.globalArguments, mirroring the runtime merge inDefaultMethodExecutionService.execute.validateModelMethodInputsunions step inputs withdefinitionProvidedArgswhen computing the missing-arg set.?? []fallback preserves backward compatibility for any existingMethodResolutionconstructions.Test Plan
validation_service_test.tscovering: definition supplies all, partial split with step inputs, partial unsatisfied (error names only the truly-missing key), step+definition overlap, and legacy-mock backward compat./tmp/swamp-repro-issue-359(command/shell model withmethods.execute.arguments.runset, workflow step with noinputs:):swamp workflow validatenow passes 8/8 andswamp workflow runstill succeeds.Missing required inputs: run.deno check,deno lint,deno fmt,deno run test(5952 passed, 0 failed),deno run compile— all green.Follow-up
systeminit/swamp-uatto cover this scenario intests/cli/workflow/validate_test.ts.🤖 Generated with Claude Code