From 09806cdc30644e0ed9fcaee21d0ee1b6e4898123 Mon Sep 17 00:00:00 2001 From: os-zhuang Date: Wed, 24 Jun 2026 23:08:26 +0800 Subject: [PATCH] docs(skill): teach the automation skill the ADR-0044 send-back-for-revision shape MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The objectstack-automation skill documented approve/reject approvals (ADR-0019) but not the ADR-0044 revise loop, so AI-authored approval flows omit it (and a revise loop hand-built without the back-edge gets rejected by registerFlow). Add a "Send-back for revision" section to the Approvals area: the `revise` out-edge → a signal `wait` node, the resubmit edge typed `type: 'back'` (the only thing that legalizes the cycle — graph-minus-back-edges must be a DAG, authors opt in edge by edge), and the `maxRevisions` budget. Calls out the two shapes the compile-time flow lint flags (dead-end revise; unmarked back-edge) and points at the canonical showcase_budget_approval. Completes the agent-teaching slice of #2274 (ADR-0044), alongside the compile-time lint (#2279), the flow-builder `back` edge style (#2291), and the engine's already-specific cycle-rejection hint. Co-Authored-By: Claude Opus 4.8 --- skills/objectstack-automation/SKILL.md | 50 ++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/skills/objectstack-automation/SKILL.md b/skills/objectstack-automation/SKILL.md index ad0d8a9a19..6e127c602e 100644 --- a/skills/objectstack-automation/SKILL.md +++ b/skills/objectstack-automation/SKILL.md @@ -297,6 +297,56 @@ is one diagram a reviewer (or AI) can read end-to-end. } ``` +### Send-back for revision (ADR-0044) + +Approval centers also model **send back for revision** (退回修改) — distinct from +`reject` (terminate) and from a comment thread (which keeps the request pending). +Send-back is a **flow movement**: the request finalizes as `returned`, the run +walks a **`revise`** out-edge to a `wait` node where the record unlocks and the +submitter reworks it, and an explicit *resubmit* re-enters the approval node over +a **declared back-edge**, opening round N+1 with a fresh approver slate. + +``` +approval ──approve──▶ … + ──reject───▶ … + ──revise───▶ wait (signal; record unlocked, submitter edits) + └──resubmit──[type:'back']──▶ approval (round N+1) +``` + +Three pieces author it: + +1. **`revise` out-edge** — a third branch label alongside `approve` / `reject`, + targeting an ordinary `wait` node (signal flavour). +2. **`type: 'back'` resubmit edge** — the edge from the wait node back into the + approval node MUST be typed `'back'`. This is the *only* thing that legalizes + the cycle: `registerFlow` validates the graph **minus `back` edges** as a DAG, + so an **unmarked** cycle is rejected — you opt in, edge by edge. At run time a + back-edge traverses normally (it just re-enters the node). +3. **`maxRevisions`** on the approval `config` (default `3`) — the budget of + send-backs per run; exceeding it **auto-rejects** (resumes down the `reject` + edge). `maxRevisions: 0` disables send-back, so never pair `0` with a `revise` + edge. + +```typescript +{ + id: 'manager_review', type: 'approval', + config: { approvers: [{ type: 'role', value: 'manager' }], lockRecord: true, maxRevisions: 2 }, +}, +{ id: 'wait_revision', type: 'wait', label: 'Awaiting Revision', + config: { eventType: 'signal', signalName: 'budget_revision' } }, +// …among the approval's edges… +{ id: 'rev', source: 'manager_review', target: 'wait_revision', label: 'revise' }, +{ id: 'back', source: 'wait_revision', target: 'manager_review', label: 'resubmit', type: 'back' }, +``` + +> Two mistakes the compile-time flow lint flags: a `revise` edge whose wait node +> never loops back (a dead end `registerFlow` accepts but that leaves the +> submitter nowhere to resubmit), and a resubmit edge left **without** +> `type: 'back'` (an unmarked cycle `registerFlow` rejects). Resubmit is an +> explicit verb (`POST /api/v1/approvals/requests/:id/resubmit`), never a +> record-save. See `examples/app-showcase` → `showcase_budget_approval` for the +> canonical shape. + ### Re-homing the old process model If you've seen the pre-ADR-0019 `ApprovalProcess.create({...})` shape, every