Repository navigation
feat: add outbound flow validation - #48
Merged
Merged
Conversation
Add an outbound profile for flows run on a call the app places, with no
person standing by: `validate::validate_outbound` (Rust) and
`validateOutbound` (TS). Each runs the base validation first and adds:
- outbound_node_not_allowed: only greeting, menu, message, hangup and
hours steps are allowed (no ring, book or transfer).
- outbound_unbounded_loop: no loop reachable from entry made only of
steps that move on without the callee (greeting, hours). Loops
through a menu are fine.
Shared cases live in conformance/vN/outbound/{valid,invalid}, run by
both languages.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QGHE3tcTFWUtjDUxNxTWNG
Rust 1.99's new clippy::double_must_use lint fires on code generated by async-trait 0.1.91, failing `clippy -D warnings`. 0.1.92 fixes it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GNFHhzw4ZsqCFnv6ERigjd
A loop through a menu was always accepted, but with nobody pressing keys (voicemail, a silent callee) the menu takes no_input every time. If that exit leads back into the loop, the call never ends. Count a menu's no_input exit as a silent move, alongside greeting and hours exits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GNFHhzw4ZsqCFnv6ERigjd
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an outbound profile validator for flows run on a call the app places (an automated outbound call: a flow does the talking, with no person standing by). Part of the outbound call-flow work; the voice daemon will consume the Rust half.
wavekat_flow::validate::validate_outbound(&Flow) -> Result<(), Vec<ValidationError>>, plusvalidate::OUTBOUND_KINDS.validateOutbound(flow, nodeRanges?) -> Issue[]andOUTBOUND_KINDS, exported from@wavekat/flow-schema.validate/validateFlowfirst and adds the outbound issues, so it is the one gate to call for an outbound flow (no need to call both).Rules
outbound_node_not_allowedgreeting,menu,message,hangup,hoursare allowed.ring(nobody to hand the call to),book(books against the inbound caller's number) andtransfer(not offered outbound yet) are refused. One issue per node, naming the node id and kind (params.kindin TS).outbound_unbounded_loopentrymade only of moves that happen without the callee: any exit of agreetingorhoursstep, or amenu'sno_inputexit (taken every time on voicemail). Reported once per node on such a cycle. A loop through a menu's digit orinvalidexits is fine: only a callee pressing keys can take it.The loop rule overlaps
trappedfor pure greeting cycles (both are reported), but also catches what the base validator accepts:hours -> greeting -> hourswithclosedescaping, which repeats forever during opening hours.In Rust these are two new
ValidationErrorvariants (OutboundNodeNotAllowed { node, kind },OutboundUnboundedLoop { node }); no new error type.Conformance
New
conformance/vN/outbound/{valid,invalid}buckets (documented inconformance/README.md), run by both runners through the outbound gate with the usual subset contract, plus the structural check. They stay out of the top-level buckets because a flow refused outbound is still a valid inbound flow.v1/outbound/valid/reminder: greeting + menu loopv2/outbound/valid/after-hours: every allowed kindv2/outbound/invalid/{ring,book,transfer}:outbound_node_not_allowedv2/outbound/invalid/hours-loop:outbound_unbounded_loop(base-valid)v2/outbound/invalid/menu-no-input-loop:outbound_unbounded_loop(base-valid; menuno_inputleads back to the greeting)v2/outbound/invalid/greeting-loop:outbound_unbounded_loop+trappedv2/outbound/invalid/dangling-exit:unknown_target(proves the base validation runs)Notes for the voice daemon (currently on 0.0.6)
Between crate 0.0.6 and 0.0.9 (main):
book::BOOK_GRANULARITY_MINSmoved 15 -> 30, sovocabulary_refs/required_assetsreturn a smaller set for the samebooknode. Per the crate README, take the crate upgrade before the authoring side takes the matching@wavekat/flow-schema.validate::required_schema_version; 0.0.9 addedbook::vocabulary_refs_on. Additive.ValidationError, which is not#[non_exhaustive]: an exhaustivematchon it outside the crate would need new arms (same as whenKindRequiresNewerSchemaarrived). Matching on.code()is unaffected.Versioning is left to release-please (
feat:-> next patch on both packages).Test plan
cargo fmt --check: cleancargo clippy --all-targets -- -D warnings: cleancargo test -p wavekat-flow: 64 unit tests passed (8 new outbound), 5 conformance tests passed (newoutbound_corpus_matches_expectations). Checked that flipping an outbound expectation makes it fail.cargo package -p wavekat-flow: builds from its tarballpnpm --filter @wavekat/flow-schema gen: no drift in generated filespnpm --filter @wavekat/flow-schema typecheck: cleanpnpm --filter @wavekat/flow-schema test: 10 files, 161 tests passed (newoutbound.test.ts, 8 tests; 11 new outbound conformance tests)pnpm --filter @wavekat/flow-schema build: ok🤖 Generated with Claude Code
https://claude.ai/code/session_01QGHE3tcTFWUtjDUxNxTWNG