Repository navigation
feat(ai): flow-authoring agent should emit the ADR-0044 revise-loop shape (revise + type:'back') #2274
Description
Context
ADR-0044 (approval send-back-for-revision) is implemented engine-side, and the Studio designer authoring is now done in objectui — authors can draw a revise branch, mark an edge type: 'back', see un-declared cycles flagged, and one-click an "add revision loop" (objectstack-ai/objectui#1954, #1955, #1958).
The remaining gap is the AI Build path. When the flow-authoring agent generates an approval flow with a send-back, it must emit the full revise-loop shape — otherwise the result is rejected at registration. This is the AI-authoring follow-up flagged in #1770 ("designer support … AI flow authoring all need the same reduced-graph rule").
Problem — the failure chain
The canonical revise loop is:
approval ──approve──▶ …
──reject───▶ …
──revise───▶ wait (signal)
└──resubmit──[type:'back']──▶ approval (round N+1)
registerFlow validates graph-minus-declared-back-edges must be a DAG. So if the agent generates the revise → wait → resubmit loop but forgets to mark the closing edge type: 'back', registerFlow hard-rejects it as an un-declared cycle. The generated flow won't save — the user gets an error instead of a working loop.
The shape knowledge exists in schemas the agent may consume (FlowEdgeSchema.type describes back; ApprovalNodeConfigSchema.maxRevisions is documented), but schema-visibility ≠ reliable generation. We need a deterministic safety net, not just prompt adherence.
Proposed work (prioritized by reliability)
- Deterministic guardrail in
packages/cli/src/utils/lint-flow-patterns.ts(its stated purpose: "guide the author — very often an AI generating templates — toward the robust pattern"). Add a revise-loop rule that detects an approval node sitting on a cycle whose closing edge is nottype: 'back', and either:- auto-repair: mark the closing edge
type: 'back'(turn a hardregisterFlowrejection into a working flow), or - structured feedback: surface the precise fix so the agent self-corrects on the next turn.
Auto-repair is preferred — it doesn't depend on the model "remembering."
- auto-repair: mark the closing edge
- Agent prompt + few-shot — add the revise-loop shape to the flow-authoring guidance and point at the canonical
examples/app-showcase/src/flows/index.ts→showcase_budget_approval. Also nudgemaxRevisionswhen areviseedge is emitted. - Spec completeness —
packages/spec/src/studio/flow-builder.zod.tsedge visual registry currently covers normal/default/fault but notback; add abackedge style so every flow-builder-protocol consumer (not just objectui's hand-rolled canvas) renders the return arc. - Eval — a small eval set: given prompts that imply send-back/rework, assert the generated flow (a) registers cleanly and (b) contains a
reviseout-edge + atype:'back'closing edge. Guards against regressions in the agent's adherence.
Acceptance criteria
- An AI-generated approval flow with a send-back registers cleanly (no un-declared-cycle rejection) — verified by the guardrail + eval.
lint-flow-patternscovers the revise-loop anti-pattern (unit-tested, like the existing [P2] Provide a declarative time-relative trigger (avoid fragile date-equality on record-change) #1874 rule).- The flow-builder spec describes the
backedge style. - Eval demonstrates reliable generation of the
revise+type:'back'shape.
References
- Parent: feat(studio): flow designer authoring for the approval revise loop (ADR-0044) #1770 (designer authoring — objectui side done)
- objectui PRs: feat(studio): author the approval revise loop in the flow designer (ADR-0044) objectui#1954 (authoring), refactor(audit): retire service-feed; sys_comment canonical (ADR-0052 §5) #1955 (simulate decisions), fix(spec): object.tenancy.tenantField is live (sql-driver), not dead — deletion paused #1958 (inline cycle surfacing)
packages/cli/src/utils/lint-flow-patterns.ts— flow anti-pattern linter (guardrail home)packages/spec/src/studio/flow-builder.zod.ts— flow-builder protocol (edge styles)packages/spec/src/automation/flow.zod.ts—FlowEdgeSchema.type('back');registerFlowDAG-modulo-back-edges rulepackages/spec/src/automation/approval.zod.ts—APPROVAL_BRANCH_LABELS(revise),maxRevisionsexamples/app-showcase/src/flows/index.ts—showcase_budget_approval(canonical shape)
Activity
feat(cli): lint ADR-0044 approval revise-loop footguns at compile time (
feat(spec): add the `back` edge style to the flow-builder canvas prot…
docs(skill): teach the automation skill the ADR-0044 send-back-for-re…
os-zhuang commentedon Jun 24, 2026
Progress — the deterministic + authoring pieces are shipped:
flow-approval-revise-{dead-end,unmarked-backedge,disabled})backedge style: feat(spec): addbackedge style to the flow-builder canvas protocol #2291skills/objectstack-automation/evals/approvals/test-revise-loop.md): docs(skill): add the first automation eval — ADR-0044 revise loop #2300registerFlowcycle error already carries the specific "mark the cycle-closing edge with type: 'back'" hint)On auto-repair — deliberately not pursued: ADR-0044 D5 mandates that an unmarked cycle is still rejected and authors opt in edge by edge, so silently marking an edge
backwould contradict the ADR. The guardrail is structured feedback (lint + registerFlow hint), not mutation.Remaining (b): an executable eval runner. Every
skills/*/evals/README.mdstill says "Not yet implemented." A runner that feeds prompts through the agent -> registers the output -> scores pass-rate across runs is a platform-level project (it benefits all skills and involves non-deterministic-LLM CI concerns), best scoped separately from this ADR. Keeping this issue open to track it.docs(skill): add the first automation eval — ADR-0044 revise loop (#2300