aYOUne

Changelog

What changed — grouped by release, filterable by component and repository.

No milestone 8
New applications

der Loeschantrag aus dem Portal bekommt einen Leser (W6, Art. 17)

Das Bewerber-Portal setzt erasureRequestedAt seit W3 und sagt im eigenen
Kommentar, der Vollzug sei W6. Bis heute hatte das Feld KEINEN Leser: der
Bewerber klickte, und danach geschah nie etwas.

Ein Antrag sticht die restliche Frist, aber NICHT die Schutzregeln — eine
eingestellte Bewerbung und eine LAUFENDE bleiben unberuehrt (wer zuruecktreten
will, nutzt withdraw; danach laeuft die Frist). Beide Faelle werden benannt
gemeldet statt verschwiegen.

Antraege werden getrennt geholt und entdoppelt, damit der Bericht 'auf Antrag'
von 'Frist abgelaufen' unterscheidet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
New applications

Recruiting-Kennzahlen + Fristen-Status an der Flaeche (W6 Reporting)

Time-to-Hire, Trichter je Stelle/Stufe, Absagequoten nach Kategorie — 13 Proben.

Gemessener Grund, warum das EIN Endpunkt ist und nicht drei Widget-Definitionen:
Time-to-Hire ist die Differenz zweier Datumsfelder, der generische Widget-Motor
kennt nur Akkumulatoren ueber EINEM Feld, und die Fluchttuer dataSource.pipeline
liest allein der Prerender-Worker (nicht platform/states). Drei Kennzahlen ueber
zwei Wege WAEREN das Parallel-System.

Flaeche: Loeschfrist + Anonymisierungs-Stempel als Spalten, Zeitraum-Filter,
Schnellfilter Anonymisiert. actionsForEntity(Applications) jetzt verdrahtet — die
Bedingung des frueheren Kommentars ist erfuellt, alle sechs Aktionen sind echt.

Gemessen statt gezaehlt: ein grep auf refuseUnimplementedAction liefert 11
Treffer, davon sind 8 Kommentare; die Messgroesse ist der IMPORT.

W2-Waechter mitgezogen und seine Positiv-Kontrolle auf applicants/merge
umgehaengt — sonst belegten die sechs not.toContain nichts mehr.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
New applications

KI-Unterstuetzung W4 — Vorpruefung, Antwort-Entwurf, Gespraechsfragen

Drei Aktionen an der Bewerbung, alle drei mit dem AGG-/Art.-22-Riegel BAULICH
statt nur im Prompt:

POST /applications/:id/actions/ai-screen -> schreibt aiScreening
POST /applications/:id/actions/ai-reply-draft -> liefert nur zurueck
POST /applications/:id/actions/ai-interview-questions -> liefert nur zurueck

- redactProtectedAttributes() entfernt die AGG-Traeger (Geburtsdatum, Anrede,
Anschrift, Staatsangehoerigkeit, Religion, Behinderung, Lichtbild) VOR dem
Modell-Aufruf. Was nicht mitreist, kann nicht gewichtet werden.
- filterInadmissibleQuestions() wirft unzulaessige Gespraechsfragen aus dem
ERGEBNIS und WEIST SIE AUS statt sie still zu schlucken.
- Eine unlesbare Modell-Antwort wird zum Fehler, nie zu score 0 — ein Rueckfall
saehe aus wie die Bewertung "ungeeignet".
- Keine der drei Aktionen ruft transitionEntity oder versendet etwas; nur
ai-screen schreibt, und nur das Feld aiScreening.

Alle drei Lesezugriffe (Bewerbung, Stelle, Bewerber) mandanten-gescopt einzeln.
Rechte kaskadenfrei ueber additionalRights, drei getrennte.

66 neue Proben mit Negativ- UND Positiv-Kontrollen; die Art.-22-Strukturprobe
ist kommentar-bewusst (der erste Wurf fiel an der eigenen Kopfzeile).
Volle Reihe 1054/1054, Bau gruen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012CLtxDVijYPDaZcJryaWjK
Fix applications

einen Fehler mit eigenem Status nicht auf 500 ueberschreiben

Gefunden an der LIVE-Probe, nicht an den 987 gruenen Proben: ein Uebergang auf eine
nicht sichtbare Kennung meldete "Error 500: Applications not found".

Ursache: `customerMongoose.findById` gibt bei Nicht-Fund kein leeres Ergebnis zurueck,
sondern WIRFT (`RessourceNotFoundError`, core methods/find/findOne.js:35) — und der
Fehler traegt seinen Status (404) bereits im zweiten super-Parameter. Der `if (!doc)`-
Zweig ist damit unerreichbar, und der pauschale 500er im Fang-Zweig machte aus JEDEM
Aufruf mit fremder oder falscher Kennung eine Dienst-Stoerung.

Der Fang-Zweig respektiert jetzt `e.status` (4xx/5xx) und protokolliert ein 4xx als
`warn` statt `error` — dieselbe Klassifikation wie im Fang-Zweig von createApplication.
Ein Bedienfehler weckt damit niemanden in der Ueberwachung.

⚠ Die Klasse ist breiter als dieser Weg — eine Parallel-Sitzung arbeitet an derselben
Sache im Kern (core-updateone-wickelt-404-in-500). Hier ist der Verbraucher behoben.

Proben 988/988. Flip-Probe: Status ignorieren faerbt genau 1 rot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Fix applications

Ablehnungen sagen im Rumpf denselben Status wie auf der Leitung

Am laufenden Dienst gemessen (2026-08-22): GET /applicationprocesses/<erfunden>
antwortete mit HTTP 404 und `meta.code: 500`. Die ay-CLI liest den Rumpf und meldete
deshalb "Error 500" fuer einen Bedienfehler — in der Ueberwachung eine Stoerung.

Ursache: der HTTP-Status kommt aus `res.locals.status` (returnResponse), der
`meta.code` aber aus `err.status || 500` (defaultAPIAnswerError) bzw. einem
HARTKODIERTEN 400 (defaultAPIAnswerRequestFailed). Beide lesen `res.locals` nicht.
Damit kam auch die ganze GUARD_STATUS-Abbildung der Motor-Ablehnungen (403/409/422)
als 400 beim Aufrufer an — der Kern von W2 war im Rumpf unsichtbar.

Neue Naht `lib/antwortMitStatus.ts` haengt den Status an den Fehler, damit
`err.status` greift; alle Ablehnungen der drei W2-Wege laufen darueber.

⚠ Die zwei Antwort-Bauer in `platform/core` sind NICHT angefasst — sie liegen
ausserhalb der claim_paths, und eine Aenderung dort traefe ~330 Verbraucher. Die
Codegen-Vorlage traegt denselben Widerspruch (actionJobOfferSend).

⚠ Der strukturelle Waechter allein reichte NICHT: eine Flip-Probe, die der Naht das
Anhaengen wegnimmt, liess ihn gruen — er prueft, DASS sie benutzt wird, nicht DASS sie
wirkt. Deshalb zusaetzlich `antwortMitStatus.test.ts` (7 Faelle inkl. Negativ-Kontrolle
am rohen Bauer). Mit ihr beisst die Flip-Probe: 6 rot.

Proben 986/986 (49 Reihen, vorher 979/48).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Fix applications

NUL-Byte aus dem Pruefer entfernen — git fuehrte die Datei als binaer

Der Dubletten-Schluessel trug ein literales NUL als Trenner. Folge: git stuft die
Datei als binaer ein und zeigt keinen Diff mehr — eine Codeueberpruefung saehe
Aenderungen daran nie. Gefunden am "Bin 0 -> 8496 bytes" im Commit-Statistik-Block,
nicht an einem Fehlschlag: Bau und Proben waren die ganze Zeit gruen.

Ersetzt durch eine verschachtelte Karte (Map<from, Set<event>>) statt eines
zusammengesetzten Schluessels — damit entfaellt die Trenner-Frage ganz. Ein
Escape half nicht: es wurde auf dem Schreibweg erneut zu einem echten NUL.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Fix applications

die neun neuen W2-Dateien nachreichen — sie fielen aus dem Vorgaenger-Commit

130e28a committete mit , und das nimmt UNVERSIONIERTE Dateien nicht auf:
die zwoelf geaenderten Dateien gingen mit, die neun neuen nicht. Der lokale Bau blieb
gruen (er sieht den Arbeitsbaum), die Kette #174 fiel mit neun — genau den neun fehlenden Dateien.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
New applications

der Bewerbungsprozess laeuft — Anlege-Naht, fuenf echte Statuswechsel, Konfigurations-Flaeche

Bewerbermanagement W2. W1 hat die Flaechen und den Prozess-Seed gebaut, aber die
Strecke war nicht bedienbar: alle sechs Aktions-Ruempfe lehnten mit 422 ab, und
`POST /applications` konnte gar nicht gelingen — das Schema fuehrt drei Pflichtfelder
(`_workflow`, `currentStatus`, `statusSince`), die kein Schreibweg setzte.

- Anlege-Naht `custom/applications/routerApplicationCreate`: loest den geltenden Prozess
ueber die dreistufige Kette auf (Stelle -> Mandanten-Kopie -> Plattform-Vorgabe),
setzt die drei Felder und loest die Eingangsbestaetigung ueber den Orchestrator aus.
Verwirft `_workflow`/`currentStatus`/`statusSince` AUS DEM RUMPF.
- Fuenf Aktionen echt ueber `core/lib/workflow/transitionEntity`
(transition/reject/send-offer/hire/withdraw); `anonymize` bleibt ehrlich abgelehnt (W6).
- Mandanten-Riegel: der Motor laedt roh (`model.findById`), die Naht laedt VORHER
ueber `customerMongoose` — sonst waere die Bewerbung eines fremden Mandanten schaltbar.
- `statusSince` + `stageHistory` werden nachgeschrieben (der Motor schreibt die Namen
des Piloten `ITask`, `strict` verwirft sie hier still).
- Konfigurations-Route `custom/applicationprocesses` (Liste/Lesen/Aendern/Uebernehmen)
mit einem Pruefer, der sieben Graph-Fehler abfaengt, die der Motor NICHT abfaengt.
- SDUI: Flaeche `hr.applicationprocesses` + Modul-Verweis; Status-Aktionen am
Bearbeitungs-Zustand verdrahtet (Hausregel "erst befuellen, dann verdrahten" erfuellt).
- Rechte `hr.applicationprocesses.view|edit` kaskadenfrei ueber `additionalRights`.

Proben 978/978 (48 Reihen, vorher 954/47). Drei Flip-Proben, je genau 1 rot, mit
nachgewiesener Ersetzung: Mandanten-Riegel, Punkt-Pfad-Riegel, Aktions-Verdrahtung.

Es gibt KEINE `ApplicationProcesses`-Entitaet und soll keine geben — das Fundament
sagt es woertlich (`IApplication`). Der Prozess IST ein `Workflows`-Dokument.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>