feat(automation-approval-steps): approval action kind, on-approve/reject follow-ups, My Approvals widget - #10
Merged
Conversation
…ect follow-ups, My Approvals widget
Adds a new `approval` automation action kind (event/lifecycle-transition
triggers only, group-only assignee) that compiles to an OpenRegister
ApprovalChain and initialises a step via ApprovalService::initializeChain()
at trigger-fire time (AutomationApprovalTriggerListener) — consume-not-rebuild
per ADR-022, no new approval engine in OpenBuild.
- AutomationCompilerService: matrix extended, approval-backend compile
branch (upsert ApprovalChain, idempotent), provenance.approvalChainName,
approvalState() for status/dry-run surfacing.
- ApprovalOutcomeListener: dispatches an automation's onApprove/onReject
follow-up actions on ApprovalStepApprovedEvent/RejectedEvent via the
shared RuleActionDispatcher.
- AutomationEditDialog: approval action type, NC-group assignee picker
(degrades to free-text), on-approve/on-reject nested action-list editors
(new AutomationActionListEditor.vue).
- MyApprovalsWidget.vue: runtime widget listing the viewer's pending
approval steps (client-side group filter via IInitialState), approve/
reject calling OpenRegister's /api/approval-steps directly — no
OpenBuild pass-through controller.
- AutomationsController::status()/dryRun(): approvalState field.
- OpenRegister test stubs extended (ApprovalChain/Step/Mapper/Service,
ApprovalStep{Approved,Rejected}Event, Object{Created,Updated}Event) so
the unit suite is self-contained without a sibling checkout.
Archives openspec change automation-approval-steps; syncs delta specs into
automation-designer (REQ-AUTD-002/003/004/007) and the new
automation-approval-action capability spec (Status: done).
This was referenced Jul 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements OpenSpec change
automation-approval-steps: a fourth automation action kind,approval, that compiles to an OpenRegisterApprovalChainand consumes OR's existing approval engine end to end — no new approval logic is built in OpenBuild (ADR-022 consume-not-rebuild).AutomationCompilerService): v1 matrix extended soapprovalis supported onobject-created|object-updated|object-deleted|lifecycle-transitiontriggers only (schedule/manualstay fail-closed). A new compile branch upserts an ORApprovalChain(aut-<slug>, one step,role= assignee group) viaApprovalChainMapper, idempotently.provenance.approvalChainNameis recorded; enable/disable/delete removes exactly that chain. NewapprovalState()reads the live aggregate state (none|pending|approved|rejected) for status/dry-run.AutomationApprovalTriggerListener, new): subscribes toObjectCreatedEvent/ObjectUpdatedEvent/ObjectDeletedEvent/ObjectTransitionedEvent, matches enabled automations by trigger shape, and callsApprovalService::initializeChain()for the fired object — with an idempotency guard so anobject-updated-triggered automation never spawns duplicate chain instances.ApprovalOutcomeListener, new): onApprovalStepApprovedEvent/ApprovalStepRejectedEvent, resolves the originating automation by itsaut-<slug>chain name (single lookup, no scan for unrelated chains) and dispatches the automation'sonApprove/onRejectfollow-up actions through the sameRuleActionDispatcherthe rules backend already uses.AutomationEditDialog.vue):approvalaction type with an NC-group assignee picker (live OCS fetch, degrades to free-text) plusonApprove/onRejectnested action-list editors (new reusableAutomationActionListEditor.vue). Matrix validation blocksapprovalonschedule/manualwith an explicit message.MyApprovalsWidget.vue, new runtime widget): lists the viewer's pendingApprovalSteps (client-side group filter viaIInitialState, never a DOM read) with approve/reject buttons that call OpenRegister's/api/approval-steps/{id}/approve|rejectdirectly — no OpenBuild pass-through controller (ADR-022 redundant-controller gate). Registered inruntimeRegistry.jswith the required ADR-049_note+@custom-widget-ratchet excludejustification.AutomationsController::status()anddryRun()both surfaceapprovalState; the dry-run panel showsapprovalas "dry-run, skipped" and creates no realApprovalStep(addedapprovaltoConditionActionExecutor::SIDE_EFFECT_ACTIONS, used only by the dry-run synthetic rule path — the real compile path never routesapprovalthrough the rules engine).tests/stubs/openregister-stubs.phpwithApprovalChain/ApprovalChainMapper/ApprovalStep/ApprovalStepMapper/ApprovalServiceand the four new Event stubs, so the unit suite is self-contained (no siblingopenregistercheckout required in CI).Archives the change: delta specs synced into
automation-designer(REQ-AUTD-002/003/004/007) and the newautomation-approval-actioncapability spec (Status: done).Test plan
docker run --rm -v $PWD:/app -w /app nextcloud:34.0.0-apache php vendor/bin/phpunit -c phpunit-unit.xml→ 672/672 pass, 0 failures/errors (1 benign "no coverage driver" warning).vendor/bin/phpcs --standard=phpcs.xmlon all touched/newlib/files → 0 errors, 0 warnings.vendor/bin/phpstan analyse --memory-limit=1Gon touched files → no errors.vendor/bin/psalm --threads=1 --no-cache(whole repo) → no errors (psalm.xml'sOCA\OpenRegister\*suppression allow-list extended for the new Approval*/Event classes).ApprovalChainGateListenerprecedent) — zero new method-level violations after refactor.npx eslint <touched .vue/.js>→ 0 errors (only pre-existing repo-wide@specjsdoc-tag warnings).npx vitest run(full suite) → 126 files / 1224 tests pass, including 5 new/updated files covering the matrix, dialog, action-list editor, and My Approvals widget.openspec validate "automation-approval-steps"→ valid;openspec status→ all artifacts done.run-hydra-gates.sh --scope-to-diff origin/development) → green (spec-coverage, redundant-controller, no-admin-idor, custom-widget-ratchet, route-auth, etc.).tests/integration/openbuild-automation-approval-steps.postman_collection.json) but not executed against a live instance this session (no deploy to the shared dev instance per project policy).tests/e2e/automations.spec.tsbut not executed this session (CI-run only, matching the pre-existing suite's own documented convention).🤖 Generated with Claude Code