Optimierung 2.6: reprocessAfterContentChange im PressReleaseService

Den 3x identischen contentChanged->fresh->reclassifyIfClassified->
rescoreIfScored-Block (admin/edit 1x, customer/edit 2x) in
PressReleaseService::reprocessAfterContentChange() zentralisiert.

Hinweis: Eine vollstaendige createDraft()/updateContent()-Verlagerung
wurde bewusst NICHT erzwungen — die Attributsaetze und der umgebende
Validierungs-/Fehlerfluss von Admin (no_export, direkter review-Status)
und Customer (placeholder_variant, Titel-Fallback, immer Draft) divergieren
real; eine gemeinsame Persistenzmethode waere fragil bei grosser Testflaeche.

Tests: 2 neue Faelle; volle Suite gruen (796 passed, 1 skipped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-06-19 10:01:29 +00:00
parent 8c53146548
commit 83d2ee659a
4 changed files with 50 additions and 12 deletions

View file

@ -106,6 +106,24 @@ class PressReleaseService
ScorePressRelease::dispatch($pressRelease->id)->onQueue('classification');
}
/**
* Nach einer inhaltlichen Änderung (Titel/Text) einer bereits geprüften
* bzw. bewerteten PM erneut prüfen (Re-Check ohne Routing) und neu
* bewerten. Operiert auf dem frischen Modellstand. Single Source of Truth
* für die vier PM-Editoren.
*/
public function reprocessAfterContentChange(PressRelease $pressRelease): void
{
$fresh = $pressRelease->fresh();
if ($fresh === null) {
return;
}
$this->reclassifyIfClassified($fresh);
$this->rescoreIfScored($fresh);
}
/**
* Routet eine frisch klassifizierte PM anhand des KI-Ergebnisses
* (Decision-Update §5.0, Entscheidung 12.06.2026). Wird vom

View file

@ -209,10 +209,7 @@ new #[Layout('components.layouts.app'), Title('Pressemitteilung bearbeiten')] cl
// Inhaltliche Änderung einer bereits geprüften/bewerteten PM → neu
// prüfen (Re-Check ohne Routing) und neu bewerten.
if ($contentChanged) {
$service = app(PressReleaseService::class);
$fresh = $pr->fresh();
$service->reclassifyIfClassified($fresh);
$service->rescoreIfScored($fresh);
app(PressReleaseService::class)->reprocessAfterContentChange($pr);
}
Flux::toast(text: __('Pressemitteilung gespeichert.'), variant: 'success');

View file

@ -273,10 +273,7 @@ new #[Layout('components.layouts.app'), Title('Pressemitteilung bearbeiten')] cl
[$pr, $contentChanged] = $result;
if ($contentChanged) {
$service = app(PressReleaseService::class);
$fresh = $pr->fresh();
$service->reclassifyIfClassified($fresh);
$service->rescoreIfScored($fresh);
app(PressReleaseService::class)->reprocessAfterContentChange($pr);
}
Flux::toast(
@ -335,10 +332,7 @@ new #[Layout('components.layouts.app'), Title('Pressemitteilung bearbeiten')] cl
// prüfen (Re-Check ohne Routing) und neu bewerten. Beim Einreichen
// übernimmt das submitForReview.
if ($contentChanged) {
$service = app(PressReleaseService::class);
$fresh = $pr->fresh();
$service->reclassifyIfClassified($fresh);
$service->rescoreIfScored($fresh);
app(PressReleaseService::class)->reprocessAfterContentChange($pr);
}
Flux::toast(

View file

@ -3,6 +3,7 @@
use App\Enums\PressReleaseClassification;
use App\Enums\PressReleaseStatus;
use App\Jobs\ClassifyPressRelease;
use App\Jobs\ScorePressRelease;
use App\Models\Category;
use App\Models\Company;
use App\Models\PressRelease;
@ -37,6 +38,34 @@ test('reclassifyIfClassified does nothing for a never-classified press release',
Queue::assertNothingPushed();
});
test('reprocessAfterContentChange reclassifies and rescores on the fresh model state', function () {
Queue::fake();
$pressRelease = PressRelease::factory()->create([
'classification' => PressReleaseClassification::Green->value,
'content_score' => 80,
'status' => PressReleaseStatus::Published->value,
]);
app(PressReleaseService::class)->reprocessAfterContentChange($pressRelease);
Queue::assertPushedOn('classification', ClassifyPressRelease::class);
Queue::assertPushedOn('classification', ScorePressRelease::class);
});
test('reprocessAfterContentChange does nothing for an unclassified, unscored press release', function () {
Queue::fake();
$pressRelease = PressRelease::factory()->create([
'classification' => null,
'content_score' => null,
]);
app(PressReleaseService::class)->reprocessAfterContentChange($pressRelease);
Queue::assertNothingPushed();
});
test('api update of a classified press release re-classifies when the content changes', function () {
/** @var TestCase $this */
Queue::fake();