Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions docs/adr/0043-actionable-approval-links.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ADR-0043: Actionable approval links — single-use tokens with a session-less confirm page

**Status**: Accepted — implemented (proposed 2026-06-12 · calibrated 2026-06-12)
**Status**: Accepted — implemented (proposed 2026-06-12 · calibrated 2026-06-12) · **Amended** (2026-10-10, #22631 — open-time notification is the approvals service's own `approval.requested` topic, not a flow-authored `notify` node; see the Issue bullet under Mechanics. One-tap links stay `remind()`-only; the token table and every decision below are unchanged)
**Deciders**: ObjectStack Protocol Architects
**Builds on**: [ADR-0042](./0042-approval-sla-escalation.md) (reserved system actors, audit-first discipline), thread interactions (#1740), [ADR-0012/0030](./0030-notification-platform-convergence.md) (messaging + outbox)
**Closes**: [#1743](https://github.com/objectstack-ai/objectstack/issues/1743)
Expand Down Expand Up @@ -37,9 +37,11 @@ GET-executes design gets requests approved by robots.
- **Issue** (`issueActionTokens`): 256-bit random raw tokens, returned
once, hashes stored. Wired into `remind()` — each pending approver with
a concrete identity (not `role:*` literals) gets their **own**
notification carrying their own approve/reject links. (Open-time
notification remains the flow author's `notify` node; templates there
can adopt the same links later.)
notification carrying their own approve/reject links. (Amended
2026-10-10, #22631: open-time notification is the approvals service's
`approval.requested` topic, published by `openNodeRequest` to each
concrete approver on the slate the request opens on — PR #22625; it
carries no links, and one-tap links remain `remind()`-only.)
- **Confirm page** (`GET /api/v1/approvals/act?token=…`): session-less
minimal HTML rendered by the plugin on the host Hono app — request
summary (flow label, record title, action) + a POST form. Invalid /
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,6 @@ Three pieces author it:
id: 'manager_review', type: 'approval', label: 'Manager Review',
config: { approvers: [{ type: 'position', value: 'manager' }], lockRecord: true, maxRevisions: 2 },
},
// No config and no `waitEventConfig`: the window ends on the submitter's
// explicit resubmit, not on a signal or a timer.
{ id: 'wait_revision', type: 'approval_revise', label: 'Awaiting Revision' },
// …among the approval's edges…
{ id: 'rev', source: 'manager_review', target: 'wait_revision', label: 'revise' },
Expand Down Expand Up @@ -379,5 +377,7 @@ These are wired on the **graph**, not in node config:
edits while pending — otherwise approvers chase a moving target.
4. **Model rejection as a visible branch** — a back-edge to revise, or an `end`
node to terminate. The path is on the diagram, not hidden in config.
5. **Notify from downstream nodes** wired to the `approve` / `reject` edges
rather than expecting the node to send mail itself.
5. **Notify the submitter from downstream nodes** wired to the `approve` /
`reject` edges. Opening already tells each resolved approver
(`approval.requested`); ⛔ no `notify` node for the opening: it tells
them twice.
Loading