The contract is rebuilt when the manifest changes, and versioned when it is
Rebuilding is triggered by the manifest, not by the schemas underneath it, so a caller reads a contract that was published deliberately rather than one that drifts.
The rule
- A workflow's contract is rebuilt when its declared input or output manifest differs from the stored one, or when a rebuild is forced.
- A change inside a bound port's own schema does not trigger a rebuild, so the published contract stays as it was until something else rebuilds it.
- A side with no declared entries stores no schema for that side.
- On rebuild the contract version is bumped: from an all-zero version any of a major, minor or patch bump yields the first released version; otherwise the named digit is incremented and the lower digits reset.
- A rebuild that bumps nothing writes the schemas and leaves the version untouched.
- A build that fails logs an error, preserves the previously published contract, and does not prevent the workflow from being saved.
What it means
The trigger is the port list, not what changed underneath it. A bound port's
own schema can change entirely — a fragment's type, its minLength,
anything a node type declares — and the published contract does not move,
because nothing rebuilds it until the input or output port list itself
differs from the one already stored, or a rebuild is forced. A caller
reading the published contract is reading what was last published, not a
live reflection of the ports it names.
A side with no declared entries stores no schema for that side at all — there is nothing to build. And a build that fails leaves the previously published contract in place: the workflow still saves, the failure is recorded, and nothing about the failed rebuild reaches the caller.
Example
[ { "name": "in", "node_id": "n1", "port": "p1" } ][ ]null