Validate a workflow¶
science-adk validate is static, instant and free. Run it after every edit —
it is the cheapest way to find a mistake that would otherwise surface halfway
through a long run.
science-adk validate # the current experiment
science-adk validate 001-my-hypothesis
science-adk validate --json
Reading the report¶
error edge fetch.planets -> analyze.planet: 'analyze' has no input port 'planet'
fix: Available inputs: planets
warn node plot: is not connected to anything
fix: Connect it, or remove it from the workflow.
Each issue has three parts: where (workflow, edge …, node …, or
file:class), what is wrong, and a fix written as an instruction.
Errors block the run; warnings do not.
Common errors and their fixes¶
Port name mismatch between class and DAG¶
error analyze.py:FitKeplerLaw: input ports ['planet'] do not match
workflow.json ['planets']
fix: The class and the DAG must agree. Update whichever is wrong.
The class's Ports(...) and the node's ports block must declare the same
names. Change whichever one is wrong — the check does not care which is
authoritative, only that they agree.
Type mismatch on an edge¶
error edge load.dataset -> train.dataset: type mismatch: json -> dataframe
fix: Change one port's type, or insert a node that converts.
Only identical types, any on either side, and int → float are accepted.
If the conversion is real, make it a node; if the declaration was sloppy, fix
the declaration.
ports without an annotation¶
error analyze.py:FitKeplerLaw: declares `ports` without a type annotation
fix: Write `ports: Ports = Ports(...)`, not `ports = Ports(...)`.
Agents are pydantic models. An unannotated assignment is not a field, so the ports would silently be empty at run time.
An unannotated class attribute¶
error analyze.py:FitKeplerLaw: class attribute `assumptions` has no type
annotation
fix: For a constant write `assumptions: ClassVar[...] = ...`; for
configuration, read it from `params` instead.
A method named run¶
error analyze.py:FitKeplerLaw: defines `run`, which belongs to the ADK runner
protocol
fix: Rename it to `execute`: `async def execute(self) -> dict:`.
execute is not async¶
error analyze.py:FitKeplerLaw: `execute` must be async
fix: Change `def execute` to `async def execute`.
Two agents in one file¶
error analyze.py: defines 2 agent classes (FitKeplerLaw, Helper)
fix: Split them into separate files: one agent per file.
One node, one file, one class. A helper that is not an agent is fine; a second
Agent subclass is not.
A required input with no edge¶
error node evaluate: required input 'settings' is not connected
fix: Add an edge into evaluate.settings, or mark the port optional.
A cycle¶
error workflow: cycle detected: analyze -> evaluate -> analyze
fix: Remove an edge to break the cycle.
Two edges into one input¶
error edge b.out -> c.in: input c.in is already fed by a.out
fix: An input port accepts exactly one edge.
If a node genuinely needs to combine two upstream values, give it two input ports.
Integrity findings¶
These come from reading the agent's AST, and they exist because each one is a way a broken run turns into a believable number.
error analyze.py:42: exception is caught and discarded
fix: Let it propagate. A swallowed error becomes a fabricated result.
warn analyze.py:51: bare `except:` catches everything, including bugs
warn fetch.py:17: calls eval()
warn fetch.py:8: suppresses warnings
The discarded exception is an error — it is the pattern that most reliably converts a failure into a fake success. The rest are warnings, and each is worth a sentence in the audit rationale if you keep it.
Warnings worth arguing with¶
| Warning | When it is acceptable |
|---|---|
has no evaluation node |
Almost never — without one, no run can be scored. |
is not connected to anything |
While a node is being built. Not at review time. |
suppresses warnings |
When you have read the warning and know precisely why it is benign. Say so. |
In the loop¶
The runner validates again before creating a run directory and refuses to start on an invalid workflow, so nothing partially executes:
error: Workflow is not valid, so nothing was run:
error workflow: cycle detected: analyze -> evaluate -> analyze