ADR-021: Editors approve their own changes in chat
Status: Accepted
Date: 2026-10-08
Context
A guided process proposes a change and the editor presses "Übernehmen". In
nr-llm a proposed write is an approval (nr-llm ADR-134), so "Übernehmen" is
the approve button of the approval card. The chat offered that card only to
administrators and to users of nr-llm's AI Tasks module
(mayDecideApprovals()): editors who should not see every run of the
installation could not apply the changes they asked for.
nr-llm itself lets the owner of a run decide it (mayActOnRun()), checks
the approver against the tool policy (nr-llm ADR-133) and, where a
configuration requires a second approver, refuses the initiator's approval
(nr-llm ADR-172). The module check is the chat's own restriction.
Decision
A new backend group permission, "Approve own changes in the chat"
(customPermOptions, stored as tx_nrmcpagent:approve_own_changes),
lets an editor decide the approvals of their own conversations. It is added
beside the module rule, not instead of it: administrators and module users
decide as before.
Approving needs the change's preview, built with the editor's rights. The brief asked for "the record permissions the write needs". nr-llm offers no question for that before the write runs; the closest signal is the approval preview, which the tool computes as the acting user and which fails, with the tool's reason, for a plan the user may not carry out. So an editor deciding by the new permission may approve only when every pending call has a preview that did not fail; otherwise the card offers the denial only and says that someone with AI Tasks can approve. This is a proxy, and it is stated as one: the write itself still runs as the conversation's owner, where TYPO3's DataHandler enforces the record permissions, and a tool without a preview stays with administrators and module users. The check is repeated on the server when the decision arrives, from the run as it waits then.
Four-eyes is shown, not discovered. In the chat the reader is always the
run's initiator. When the run's configuration requires a second approver
(read from the run's own configurationUid), the card offers no approve
button to anyone and names AI Tasks, where a colleague approves; the denial
stays, as nr-llm allows it. A refusal nr-llm still returns
(SelfApprovalDeniedException) is a hand-back that keeps the card, no
longer a failed conversation.
Consequences
- Integrators grant the permission per backend group under "Custom module options".
getMessages()returnspendingApproval.approveBlocked:'',secondApproverorpreview.- An editor with the permission sees the card, may always deny, and may approve changes nr-llm could preview for them.