ki/quota: Hash-Bindung atomar bis in den Publish-Lock, roter Re-Check lehnt ab, Kontingent-Altbestand (Block 7, U02–U04)
- Jobs speichern Ergebnis nur per bedingtem UPDATE auf den analysierten Hash; publish() prüft bei ki/scheduler unter der Zeilensperre die jüngste gültige Klassifikation und plant sonst eine neue Prüfung ein (StaleClassificationException) - Re-Check ohne Routing: Rot bei einer PM in Review lehnt wie die Erstprüfung ab - consumePublishSlot() zählt eine NULL-Periode wie den laufenden Monat; Backfill-Migration setzt die Periode für Altverbrauch - ApiPortalResolutionTest: gemeinsame Kategorie wegen der U10-Prüfung Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
eb95b3b830
commit
082e6bb76c
11 changed files with 698 additions and 25 deletions
|
|
@ -25,6 +25,9 @@ use Illuminate\Support\Facades\Log;
|
|||
*
|
||||
* Inhaltsbindung wie bei ClassifyPressRelease (Audit F07): Ergebnis für
|
||||
* einen inzwischen geänderten Text wird verworfen und neu eingeplant.
|
||||
* Atomar per bedingtem UPDATE auf die geprüfte Prüfsumme (Audit U02); der
|
||||
* KI-Aufruf läuft außerhalb jeder Sperre. Query-Builder-Update ist hier
|
||||
* unbedenklich: kein Observer reagiert auf Score-Felder.
|
||||
*/
|
||||
class ScorePressRelease implements ShouldQueue
|
||||
{
|
||||
|
|
@ -57,9 +60,28 @@ class ScorePressRelease implements ShouldQueue
|
|||
$result = $this->score($manager, $pressRelease);
|
||||
$tier = PressReleaseContentTier::fromScore($result->score);
|
||||
|
||||
$currentHash = PressRelease::withoutGlobalScope(PortalScope::class)->whereKey($pressRelease->id)->value('content_hash');
|
||||
// Bedingtes UPDATE: schreibt nur, wenn der Inhalt noch die bewertete
|
||||
// Prüfsumme trägt. Altbestand ohne Summe (null) wird unbedingt
|
||||
// geschrieben. 0 Zeilen = Inhalt inzwischen geändert oder PM weg.
|
||||
$scoredAt = now();
|
||||
$stored = PressRelease::withoutGlobalScope(PortalScope::class)
|
||||
->whereKey($pressRelease->id)
|
||||
->when($analyzedHash !== null, fn ($query) => $query->where('content_hash', $analyzedHash))
|
||||
->update([
|
||||
'content_score' => $result->score,
|
||||
'content_tier' => $tier->value,
|
||||
'scored_at' => $scoredAt,
|
||||
'updated_at' => $scoredAt,
|
||||
]);
|
||||
|
||||
if ($stored === 0) {
|
||||
$currentHash = PressRelease::withoutGlobalScope(PortalScope::class)->withTrashed()->whereKey($pressRelease->id)->value('content_hash');
|
||||
|
||||
if ($currentHash === null) {
|
||||
// Hart gelöscht: nichts mehr zu binden, kein Audit möglich (FK).
|
||||
return;
|
||||
}
|
||||
|
||||
if ($analyzedHash !== null && $currentHash !== null && $currentHash !== $analyzedHash) {
|
||||
KiAudit::query()->create([
|
||||
'press_release_id' => $pressRelease->id,
|
||||
'type' => KiAudit::TYPE_CONTENT_SCORE,
|
||||
|
|
@ -78,12 +100,6 @@ class ScorePressRelease implements ShouldQueue
|
|||
return;
|
||||
}
|
||||
|
||||
$pressRelease->forceFill([
|
||||
'content_score' => $result->score,
|
||||
'content_tier' => $tier->value,
|
||||
'scored_at' => now(),
|
||||
])->save();
|
||||
|
||||
KiAudit::query()->create([
|
||||
'press_release_id' => $pressRelease->id,
|
||||
'type' => KiAudit::TYPE_CONTENT_SCORE,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue