Voller 3-Achsen-Review (post-reconcile) — mp/P2503-90 Pfad A

Vacancy Application · direkter Personio-Recruiting-API-POST · PR #165066develop · Fixed-Point origin/develop · 2026-05-30 · Source: ADR-0028

VERDICT: CLEAN — keine BLOCKERS, review-ready

Der volle 3-Achsen-Review (Standards · Canvas · Spec), der nach dem streamlined drupal-php-reviewer-Pass (pfad-a-review, supersedet) noch ausstand — gefahren auf dem finalen Diff (10.953 Insertions / 65 Files) nach dem Contract-Reconcile auf User-Decisions: sent($idempotencyKey) als lokaler Send-Token (Personio liefert beim 201 keine ID, kein Read-back) und Files-live via Flag personio_send_documents. Canvas-Achse inaktiv (keine canvas.*/.component.yml-Files im Diff).

Layer-Evals (verifiziert)

GateErgebnis
PHPUnit Kernel (gesamtes Modul)OK 27 Tests / 217 Assertions, 0 Failures (15 bekannte Deprecations)
phpcs (pre-commit hook)clean 0 Errors
phpstan (phpstan.neon)No errors
Live-Feature-Re-Test (Sandbox, Job 2635453)PASS Submission+CV → queue:run → 2xx + Send-Token im Feld + GDPR-Purge + Submission gelöscht

Standards

Keine HARD violations. DI durchgängig korrekt (Services, QueueWorker via ContainerFactoryPluginInterface, Drush-Commands, Controller); Routing — alle state-ändernden DLQ-Routen via ConfirmFormBase (POST + CSRF), Apply/Thank-You via _custom_access, DLQ-Listing via _permission; manage karriere dlq in permissions.yml; key:key in info.yml; Config-Schema deckt alle drei Settings-Felder; keine Superglobals; kein hook_update_N nötig (neues Modul).

KlasseFindingDisposition
Judgement@WebformHandler-Doc-Annotation statt PHP-AttributSKIP Webform-Contrib-Plugin-Manager ist selbst annotation-basiert; ein Attribut würde nicht registrieren — korrekt-by-convention bis Webform migriert
Advisorykey.key.solcom_personio_api_key.yml mit dependencies: {}OK konsistent mit den 3 bestehenden key.key.solcom_sf_*-Configs (Site-Pattern)
Advisorypersonio_send_documents-Kill-Switch ohne Inline-Rationale-KommentarWORKLOG in ADR-0050 + README dokumentiert; Inline-Comment minor

Canvas-Korrektheit

Achse inaktiv — keine config/sync/canvas.* oder *.component.yml im Diff.

Spec

Spec-treu zu F-100 + ADR-0050; kein Scope-Creep. Der C+-Stack (PersonioMailBuilder/PersonioWebhookController/PersonioWebhookCommands) ist sauber entfernt. „Keine Personio-Application-ID gespeichert" ist korrekt-per-Contract (live verifiziert: 201 leer, kein Read-back), kein Spec-Gap.

KlasseFindingDisposition
MissingAK-12 — DLQ zeigt File-Presence Ja/Nein, keinen CV-Download-Link → HR kann CV für fehlgeschlagene Bewerbung nicht abrufenFOLLOW-UP echter Gap; bei Erfolg geht CV jetzt an Personio (files-live), aber DLQ-Recovery braucht Download → P90-Folge-Item
MissingAK-1 — Apply-CTA (field_apply_url) nicht auf interne Sub-Route umverdrahtetDEFERRED vorab-bekannt (Re-Grill G7, eigener Slice)
MissingAK-17 — AVV-Context-Snapshot fehlt in docs/context/DEFERRED vorab-bekannte Vorbedingung
Wrong (minor)AK-6upload_location ist flach private://applications/ (kein per-UUID-Token) → Files co-minglen; zudem private://-Stream-Wrapper im DDEV nicht konfiguriert (ApplicationPurger:99-Warning)FOLLOW-UP P90-14; Purger-is_dir()-Guard macht Removal zum sicheren No-Op, Entity-Delete räumt Files
Wrong (minor)C-3#access-Flag-Structural-Test prüft inline-Test-Webforms, nicht die installierte webform.webform.vacancy_application.ymlWORKLOG Config selbst korrekt (alle 5 Lifecycle-Elemente tragen den Flag); der vom ADR mandatierte Config-Load-Test fehlt

Summary

Findings: standards=3 (0 hard, 1 judgement, 2 advisory), canvas=inaktiv, spec=5 (3 missing pre-disclosed/deferred, 0 scope-creep, 2 minor wrong-impl). Worst: AK-12 — DLQ ohne CV-Download, HR kann CV einer fehlgeschlagenen Bewerbung nicht abrufen.

Fazit

Der Contract-Reconcile ist sauber: 0 HARD violations, kein Scope-Creep, spec-treu, alle Layer-Evals grün, Live-Feature-Re-Test PASS. Die Findings sind allesamt vorab-bekannte Deferrals (AK-1/AK-17) oder File-Storage-Folge-Items (AK-12 DLQ-Download, flat upload_location + private://-Wrapper) — orthogonal zum reconcileden API-Contract. Der PR ist review-ready. Der Merge bleibt menschlich (Memory feedback_ki_merged_nicht_bis_mr).