feat(approvals+automation): flow-level send-back-for-revision — revise branch + typed back-edge re-entry (ADR-0044)#1769
Merged
Conversation
…e branch + typed back-edge re-entry (ADR-0044) Closes #1744. - ADR-0044: returned status, revise branch label, wait+resubmit selection, __round snapshot numbering, back-edge engine semantics, interaction matrix - spec: FlowEdgeSchema type 'back'; APPROVAL_BRANCH_LABELS.revise/resubmit; ApprovalNodeConfig.maxRevisions (default 3); ApprovalStatus 'returned'; ApprovalActionKind 'revise'/'resubmit'; IApprovalService.sendBack/resubmit - engine: cycle validation on the graph minus declared back-edges (unmarked cycles still rejected); top-level re-entry runaway guard (100); cancelRun() primitive — first run-cancel, used by recall crossing a revise window - plugin-approvals: sendBack() finalizes the round as 'returned' and resumes down revise (auto-rejects past maxRevisions); resubmit() re-enters the approval node over the back-edge opening round N+1 (fresh approver slate, re-lock); collision guard refuses resubmit while another pending request holds the record (before the suspension is consumed); recall extends to the latest returned request via cancelRun; __round stamped on the config snapshot and surfaced as row.round; sys object enums synced (returned, revise, resubmit) - fix: orderBy used non-canonical `direction:` key (SortNode strips it → asc) in remind() cool-down + assertLatestForRun; regression tests - rest: POST /approvals/requests/:id/revise and /resubmit - showcase: budget approval manager step gains the revise loop (wait_revision + back-edge, maxRevisions 2) - tests: ADR-0039-style matrix — multi-round rounds 1→3, unanimous slate reset, lock lifecycle, recall crossing the window, superseded rows, overflow auto-reject, no-revise-edge rejection, engine back-edge suite Browser-verified end-to-end on the showcase stack: send back → record unlocks → edit → resubmit → round 2 approve; third send-back auto-rejects. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This was referenced Jun 12, 2026
feat(console): send back for revision in the approvals inbox (ADR-0044)
objectstack-ai/objectui#1665
Merged
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.
Closes #1744. Implements ADR-0044 (docs/adr/0044-approval-send-back-for-revision.md).
What
requestInfo()(#1740) is a thread conversation; this lands the real flow movement mainstream approval centers call 退回修改 / send back for revision:Decisions (ADR-0044)
returned— third terminalApprovalStatus(approver-initiated rework ≠ submitter-initiatedrecalled); lock + pending-dedupe key onpending, so unlock/round-N+1 need no lock-machinery changerevisebranch +maxRevisions(default 3) on the node config — overflow auto-rejects (resumes downreject,output.autoRejected: true); send-back validated against the flow graph before any mutation (no revise edge ⇒VALIDATION_FAILED)POST …/revise,POST …/resubmit; revise window is visible flow state__roundconfig-snapshot numbering —row.round, no migration (precedent:__flowLabel)FlowEdgeSchema.type: 'back'; cycle validation = DAG on the graph minus back-edges (unmarked cycles still rejected); re-entry overwrites node outputs / appends steps; 100-re-entry runaway guard;cancelRun()lands as the first run-cancel primitive (recall crossing a revise window cancels the parked run — the wait node has no reject edge)DUPLICATE_REQUESTwhile another pending request holds the record (refuses before the suspension is consumed, so the run stays resumable)Also fixes a latent orderBy bug (
direction:is not a SortNode key — silently sorted asc) inremind()'s cool-down and the new latest-row guard, with regression tests.Tests
approval-revise.test.ts): multi-round 1→3 · unanimous slate reset · lock locked→unlocked→re-locked · recall crossing the window · superseded rows · overflow auto-reject · no-revise-edge rejection · resubmit collision guard (83 ✓)Browser-verified (showcase stack, 3700/5790)
Send back from the inbox (violet
returnedbadge, timelinereviseentry) → record unlocks (PATCH 200 while returned, 409 while pending) → resubmit from the submitter view → round 2 opens (Round-2 chip, fresh trail, re-lock, survives server restart via the durable store) → round-2 approve completes the flow. Third send-back onmaxRevisions: 2auto-rejects with the audit trailrevise → reject ("Auto-rejected: revision limit (2) exceeded").Console UI counterpart: objectui PR (send-back button/dialog, resubmit entry, timeline, ten-locale i18n). Studio designer authoring for the revise edge is a follow-up issue.
🤖 Generated with Claude Code