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

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 reject → flag_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>

This branch was successfully deployed

1 active deployment
Preview — 99b688f0 Deployed Jun 11, 2026 by vercel[bot]
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