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 onesys_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

vercelBot commented Jun 11, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJun 11, 2026 3:58am

Request Review

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation size/m labels Jun 11, 2026
@os-zhuang
os-zhuang merged commit 17a8f00 into mainJun 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 freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/m

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@os-zhuang