fix(approvals): resolve field/manager approvers against the live record at node entry (#3447)#3495
Merged
Merged
Conversation
…rd at node entry (#3447) Approval nodes resolved `field` / `manager` approvers against the trigger snapshot the flow froze into `$record` at submit time, so an earlier step could not set the field a later step routes on — dynamic routing / dynamic co-sign were impossible to express. Resolution was already lazy per-node; the defect was the data source (a frozen snapshot, never re-read), betrayed by graph approvers resolving live in the same node while field/manager read the snapshot. Re-read the record's live state by id at node entry under system identity, with a warn-and-fall-back-to-snapshot path when the record is gone. Also fan a multi-select user field into one approver slot per user (previously stringified to one bogus id) and apply OOO delegation per fanned-out user (previously silently skipped for multi-value fields). payload_json still snapshots the submitted record — its contract is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 4 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
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.
What
Approval nodes resolved
field/managerapprovers against the trigger snapshot the flow froze into$recordat submit time. Once a run was in flight, nothing an earlier step wrote could reach a later approval node's approver resolution — so dynamic routing (one step decides the next step's approvers), dynamic co-sign, and "pick the co-review departments mid-flow" were all impossible to express declaratively. Fixes #3447.Root cause
Resolution timing was already lazy / per-node — each approval node resolves on entry via
openNodeRequest→expandApprovers. The defect was the data source: the node readsvariables.get('$record'), seeded once at flow start and carried verbatim through every suspend / resume, never re-read from the DB.{type:'field'}just indexed that frozen object.Tell-tale that this was a leftover and not a design choice: in the same node,
team/department/positionapprovers query the graph live, whilefield/managerread the frozen snapshot.Change (P1)
loadLiveRecord, system identity — approver routing is a platform concern and the record is the flow's own subject, so submitter RLS/FLS must not narrow it).field/managernow bind to current data; graph types were already live.payload_jsonstill snapshotsinput.record— its contract is "the record as submitted", deliberately unchanged.Two latent defects fixed on the same path
String(['u1','u2'])→'u1,u2'happened to match thepending_approversCSV format. Now fans out explicitly into one slot per user.'u1,u2'string was looked up as one delegator id. Now applied per fanned-out user.Tests
6 new tests. Verified they go red against the pre-fix implementation (stash the impl, keep the tests): 5 red (live-read, live-wins-over-stale-snapshot, array fan-out, CSV fan-out, per-user OOO) and 1 green (snapshot fallback — behaviour intentionally unchanged). Full suite 142 passed;
tsupDTS build (type-check) green.Not in this PR
P2 (
type: 'expression'approvers evaluated over flow variables + a node-level empty-approver policy) and P3 (resolver hook) are the more general evolutions; both are written up on #3447 for follow-up. This PR is the minimal P1 that fixes the reported scenario.🤖 Generated with Claude Code