# description
Every field is optional; omitted fields are left alone. Changing `trigger` or `steps` bumps the sequence's version, and contacts already in flight keep walking the version they started on.

# properties.input.description
The sequence's input signature: the shape every door must supply. A sequence is a function and this is how you declare its parameters — steps then read them as {{input.field}}, and a condition can branch on them. Omit it entirely for "anything goes"; you should not need a schema to write a two-step drip.

# properties.triggers.description
Doors into this sequence. A bare string is shorthand for { "event": "<name>" }. Replacing the set never bumps the sequence's version and never touches an enrollment in flight. A sequence with no triggers is enrolled only by naming it on a send or calling enroll — which is what "manual" used to mean.

# properties.reentry.description
`once` (default) refuses to enroll a contact already in flight. `always` restarts them: the in-flight enrollment is canceled and a new one begins. `cooldown:<duration>` (e.g. "cooldown:30 days") re-enrolls only when that long has passed since their last enrollment.

# properties.exitOn.description
Sequence-level exits, evaluated before EVERY step. `goal` completes the enrollment — they did the thing, stop chasing, which is the difference between a dunning sequence and harassment. `cancel` abandons it.