Skip to content

feat(showcase): parallel approval example + docs (ADR-0037 Track A)#1708

Merged
os-zhuang merged 1 commit into
mainfrom
feat-showcase-parallel-approval
Jun 11, 2026
Merged

feat(showcase): parallel approval example + docs (ADR-0037 Track A)#1708
os-zhuang merged 1 commit into
mainfrom
feat-showcase-parallel-approval

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Summary

First step of ADR-0037 Track A: prove and showcase that parallel approvals ("finance AND legal sign off concurrently") work today as a single aggregating approval node — no engine-core change, no token tree.

behavior: 'unanimous' over two approver groups opens one sys_approval_request whose pending_approvers lists both groups (notified in parallel) and stays suspended until both approve. This is the Camunda multi-instance / Step Functions Map pattern: one program counter, one pause/resume.

Changes

  • showcase_invoice_signoff — on invoice send, one approval node aggregates finance + legal (unanimous); approve → notify, reject → flag held.
  • flow guide: "Parallel approvals — one aggregating node" section, with a pointer to ADR-0037 Track B for the larger pause-inside-region capability.

No engine/service code: the unanimous-over-N-groups aggregation already exists and is unit-tested (approval-service.test.ts).

Test plan

  • Browser E2E (live showcase): sending an invoice opens one request with [role:finance, role:legal] pending → approving finance keeps it paused with legal still pending → approving legal resumes to completed (start → dual_signoff → notify_cleared).
  • Reject path: one rejection resumes down rejectflag_held sets the invoice back to draft → completed.
  • pnpm --filter @objectstack/docs build green; flow registers + validates at backend boot (the two pre-existing pages/*.page.ts tsc errors are unrelated to this change).

🤖 Generated with Claude Code

"Finance AND legal sign off concurrently" is one `approval` node with two
approver groups and behavior: 'unanimous' — not two parallel pauses. ADR-0037's
Track A: the aggregating-node pattern (Camunda multi-instance / Step Functions
Map) covers parallel/batch approvals with the engine's existing single
program counter, no token tree.

- showcase_invoice_signoff: on invoice send, one approval node opens a single
  request listing both finance + legal in pending_approvers (notified in
  parallel); unanimous holds until both approve, then resumes down `approve`
  (→ notify); any rejection resumes down `reject` (→ flag held).
- flow guide: new "Parallel approvals — one aggregating node" section with the
  config and a pointer to ADR-0037 Track B for the larger pause-inside-region
  capability.

No engine/service change — the unanimous-over-N-groups aggregation already
exists and is unit-tested (approval-service.test.ts). Browser-verified live:
one request with [role:finance, role:legal] pending; approving finance keeps it
paused with legal still pending; approving legal resumes to completed; the
reject path flags and completes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 11, 2026 3:58am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation size/m labels Jun 11, 2026
@os-zhuang os-zhuang merged commit 17a8f00 into main Jun 11, 2026
12 checks passed
@os-zhuang os-zhuang deleted the feat-showcase-parallel-approval branch June 11, 2026 04:02
os-zhuang added a commit that referenced this pull request Jun 11, 2026
Building A2 surfaced a real error in the ADR: it claimed Track A's `map` /
multi-instance node needs "no change to the engine's execution model." Examined
against the resume/bubble code, that is false for any map that serves batch
approval (each item can pause):

- concurrent map needs durable N:1 aggregation + per-parent serialization +
  completion-ordering handling (part of Track B's hard concurrency, confined to
  one node);
- sequential map needs resume-INTO-the-node (next item) instead of the engine's
  resume-past-the-node default (the DAG has no back-edge to loop the node);
- only a synchronous, non-pausing map is engine-free, and that does not serve
  batch approval.

Splits Track A into A1 (aggregating approval — truly free, shipped #1708) and
A2 (map node — a bounded, separately-justified engine task, design-first). A1
covers parallel approvals at zero engine cost; A2 is not a free rider on it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant