Freigabe durch die Leitung innerhalb von Grenzen (#687)

- UnitConfig.Approvals: Operationen, Hoechstzahl je Tag, Stunden je Freigabe; nur der
  Mensch setzt sie (OrgAdministration.SetApprovals mit Audit, Teilmengenregel nach oben,
  Senken oben senkt unten mit; Agentenaenderungen/Sonderbudget nie freigebbar)
- LeadApprovals: Vorlage geht an die naechste Leitung, deren Einheit die Operation
  erlaubt; nie eigene Aufrufe, nie eine Leitung mit Fremdinhalt, Tagesdeckel, Frist.
  Entscheidung ueber Escalation approve_call/reject_call, im Audit als lead:<id>
- Der Mensch sieht alles und kann zuerst entscheiden; danach wird die Leitungsaufgabe
  geschlossen. Nach der Frist nur noch der Mensch.
- StagedCalls: Approver, ApproverUntil, ApproverTaskId (Nachruestung)
- WebUI: Hinweis "bei Leitung" in der Freigabestelle, Zaehler ohne diese, Quote je
  Leitung; Karte in der Organisationsansicht; i18n en/de
- Tests: LeadApprovalsTests (13), OrgAdministrationTests (+2)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-09-30 20:12:18 +02:00
co-authored by Claude Opus 5.5
parent dafb8241a0
commit f51186269c
27 changed files with 948 additions and 20 deletions
@@ -66,6 +66,12 @@ public static class OrgBriefing
if (org.LedBy(agentId) is { } led)
{
sb.AppendLine($"You lead the unit \"{led.Name}\". Delegate within it, and hand what goes beyond it to your own lead.");
// #687: What the unit lets its lead approve — told, so an approval task is no surprise.
if (led.Approvals is { Operations.Count: > 0 } approvals && canEscalate)
sb.AppendLine($"Your unit lets you approve, for the agents below you: {string.Join(", ", approvals.Operations)} " +
$"(up to {approvals.PerDay} a day; you have {approvals.Window.TotalHours:0.##} h each, then a human decides). " +
"Check each call against the agent's task and run, not its own account. Never your own calls. " +
"An approval you give is recorded as yours, and how often you approve is watched.");
var subUnits = org.Children(led.Id);
if (subUnits.Count > 0)
{