feat(subflow): let a parent override a child's long-poll window/roles and scoped views - #1028
Conversation
…rides Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ne stamp parser Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ry surface Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… child-side Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on-blocking warnings Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e the view-key map Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…se transition alias for view override lookup Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The fallback job was armed with an instant that was never written to its InstanceJobs row, so the deadline was invisible in the database. One instant now feeds both the Dapr schedule and InstanceJob.ExecuteAt. Also documents that role headers on a runtime-started child are the consuming parent's responsibility (via its input mapping). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
|
Overall Grade |
Security Reliability Complexity Hygiene |
Code Review Summary
| Analyzer | Status | Updated (UTC) | Details |
|---|---|---|---|
| C# | Sep 23, 2026 8:33p.m. | Review ↗ |
Important
AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.
|
Brings the branch up to date with master (#1027 authorize single decision point, #1028 subflow long-poll/view overrides, #1029 state-function annotations + Aether 1.0.42). Sole conflict was docs/README.md's numbered index: kept master's "18. The authorize Function" insertion and its renumbering, appended the flow-telemetry entries as 43 (Transition and State Metrics) and 44 (Function Execution Metrics). features.json, WorkflowLogs.cs and InstanceQueryAppService.cs auto-merged cleanly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>


Summary
overrides.states.<childState>.interaction.longPoll.fallbackTimeoutSecondsand.roles. This is a field-level override: a field left out keeps the child's value, androlesreplaces the child's list as a whole.overrides.states.<childState>.viewsandoverrides.transitions.<childTransition>.views. These swap the view the child's own rules selected, keyed by that view's key.rule, and neither isterminate. An override never adds a long-poll to a state that does not declare one; that case logs 20305. If the child authorizes the long-poll with arule, arolesoverride is ignored (logs 20306) and a window override still applies.SubflowStarteralready writes onto the child (subflow.state_role_overrides/subflow.transition_role_overrides, which carry the whole maps), so there is no new stamp key. They are resolved child-side on the child's ownCurrentState, neverEffectiveState. They therefore also apply when the child is addressed directly, and reach exactly one hop: in P → C → G, P's overrides never affect G.overrides.views/viewOverridesview-key map is unchanged: it is still applied parent-side and is now deprecated invnext-meta. Mixing it with the new scoped view overrides on the same subFlow is a validation error.ExecuteAt. It is the same instant the Dapr job is armed with; before this it was always NULL.Changes
SubFlowLongPollOverrideandSubFlowStateInteractionOverrideare new.SubFlowStateOverridegainsInteractionandViews;SubFlowTransitionOverridegainsViews.SubFlowOverrideStamp(Domain). BothSubFlow*OverrideReaderclasses delegate to it. Behaviour note: a malformed grant (ArgumentException) now degrades to "no override", the same as aJsonExceptionalready did, instead of escaping.Instance.ResolveEffectiveLongPoll(state)andInstance.ResolveViewOverride(state, transition, viewKey).HandleLongPollTerminationStep: the pause (arm), the roles ownership check and the fallback schedule.LongPollInteractionGate: used by the state function and byauthorize?ack=true.ResolveInteractionAsync:fallbackTimeoutSecondsin the state body.ResolveViewAsyncapplies the override after the child's rules pick a view. A transition alias is normalised to the configured key. If the override cannot be resolved, the child's own view is served and 20101 is logged.GetSubFlowViewWithOverrideAsync(legacy) is untouched.WorkflowValidator.ValidateSubFlowOverrides: the window must be ≥ 1, the role grants are validated, and legacy and scoped view overrides may not be mixed.WorkflowValidationResult.Warnings→ComponentValidationResult.Warnings).DefinitionAppServicelogs the warnings (90006); the publish response is unchanged. First user:roles: [].docs/domain/subflow-overrides.md, plus updates todocs/domain/long-poll-termination.md,docs/README.mdand.claude/rules/vnext-workflow-developer.md. The rule file also had a staleResponseShapeVersionvalue, corrected tov11.vnext-meta/features.jsongetsengine.subFlowOverrides;deprecations.jsongets two entries. Both use version0.0.95, because tags reach v0.0.94.ResponseShapeVersionbump and no new fingerprint member.Test Plan
roles: []empty;ExecuteAtpersisted on the job row.dotnet testcompared againstmasterat the branch base: 0 new failures. Branch: 5336 total / 71 failed; master: 5302 / 81. All remaining failures fail on master too.vnext-metavalidation passes. The only drift it reports existed before this branch:common.propssays 0.0.92,version-manifeststops at 0.0.93.Integration test evidence
vnext-exampleTests/SubflowOverrideLab, run with--filter FullyQualifiedName~SubflowOverrideLab. It is a new scenario: extendingauthorization-chain-labwould have changed that suite's ack contract.e7cb023cand5f60ab4b, atVNEXT_BASE_URL=http://localhost:4201(run-docker.sh up core, local build).subflow_override_lab_child.InstanceJobs(JobType=4) has 10/10 rows withExecuteAtset, versus 0/22 before.ExecuteAt − CreatedAtis 600.0 / 120.0 / 5.0 s.authorize?ack=trueadmits, both through the parent and on the child directly. State and transition view overrides take effect, including on the directly addressed child. P's override does not reach G. The legacy map behaves as before.TEST-SCENARIOS.mdrow added: yes — test(subflow-override-lab): cover parent long-poll and scoped view overrides end to end vnext-example#22.Notes
subFlowStateOverride/subFlowTransitionOverridehaveadditionalProperties: false, and vnext-schema 0.0.52 rejects the new fields innpm run validate. The schema change is feat(schema): subflow long-poll and state/transition-scoped view overrides vnext-schema#139. Shipping the runtime first is safe: the fields are additive, and older runtimes ignore them in the stamp.SubflowStartersends only the headers the mapping supplies. This is the consuming parent's business decision; the runtime does not carry caller roles across the subflow start.HasTransitionRoleOverrides/HasQueryRoleOverridesare now also true for maps that hold only views or interaction entries, so the names mislead.🤖 Generated with Claude Code