dev: Entwicklungsplan Block 8 — Abgleich Umsetzungsaudit 25.09., Entscheidungen E10–E18, Live-Schritte, Protokoll
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
2a2215b3c3
commit
c38bcebf12
1 changed files with 69 additions and 1 deletions
|
|
@ -231,6 +231,56 @@ Nicht aufgenommen aus Block 7: U05–U07, weil das Kampagnenmodul nicht in Betri
|
|||
|
||||
---
|
||||
|
||||
## Block 8 — Nacharbeit aus dem Umsetzungsaudit vom 25.09.2026
|
||||
|
||||
Grundlage: [`UMSETZUNGSAUDIT-2026-09-25.md`](UMSETZUNGSAUDIT-2026-09-25.md) (22 Befunde: 4 × P1, 18 × P2, dazu Abschnitt 5 mit Optimierungen). Jeder Befund wurde am 25.09.2026 am Code gegengeprüft, bevor etwas geändert wurde; Plan Fassung 2 und Decision-Update vom 22.09. wurden auf abweichende Entscheidungen durchgesehen. Ergebnis: **alle 22 Befunde bestätigt, keiner war anders entschieden.** Zwei Befunde (N13, 5.1 a) sind Lücken zwischen einer eigenen Entscheidung (O1, E-B10) und ihrer Umsetzung.
|
||||
|
||||
### Abgleich
|
||||
|
||||
| Nr. | Ergebnis | Umsetzung |
|
||||
|---|---|---|
|
||||
| N01 (P1) | bestätigt | Gemeinsamer Freigabezustand `PressReleaseImage::isPubliclyDeliverable()` (nicht zurückgehalten; v2 nur mit Rechtebestätigung; Bestand `rules_version` NULL bleibt sichtbar), Scope gleichlautend; Medienroute wendet ihn an, nicht freigegebene Bilder nur mit Signatur/`view`-Recht und `private, no-store`. Cache-Lebensdauer öffentlicher Medien unverändert (E17). |
|
||||
| N02 (P1) | bestätigt | `tombstone()` liest den Eintrag unter `lockForUpdate` neu und prüft Hold, Frist und Tombstone erneut; Hold setzen/aufheben in Transaktion mit Sperre, Hold auf Tombstone wird abgelehnt. |
|
||||
| N03 (P1) | bestätigt | Bedingtes UPDATE, `syncOriginal` und Audit-INSERT in einer Transaktion (Klassifikation und Score); Re-Dispatch erst nach Commit. Keine neue Regel „ohne Audit-Hash kein Auto-Publish" (E11). |
|
||||
| N04 (P2) | bestätigt | Erwarteter Hash bis in `reject()`/`holdForManualReview()` unter der Sperre; Abweichung → `StaleClassificationException` + Re-Check für den aktuellen Stand (`rescheduleForCurrentContent()`); Vorprüfung in `redRecheckMustReject()`. |
|
||||
| N05 (P2) | bestätigt | Eigene Ability `confirmImageRights` (nur Kontoinhaber, auch bei Published; Super-Admin-Kurzschluss in Policy und globalem `Gate::before` ausgenommen); Service prüft Identität und ausstehende Bestätigung selbst (E10). |
|
||||
| N06 (P2) | bestätigt | Livewire-Komponenten tragen die gezeigten Fassungen (`legalAcceptanceVersions` per Trait-Hook `rendering`, `legalTextKey`/`imageLegalTextKey` als `#[Locked]`); Abweichung beim Absenden → Ablehnung, neuer Wortlaut wird gezeigt. Fehlendes Pflichtdokument bei aktivem Gate ist ein Konfigurationsfehler. |
|
||||
| N07 (P2) | bestätigt | `store(..., allowedStatuses)`: Status-Regel des Aufrufers wird unter der PM-Sperre erneut geprüft; nach Kundenbestätigung an veröffentlichter PM folgt der Veröffentlichungssnapshot. |
|
||||
| N08 (P2) | bestätigt | Cache-Invalidierung nach dem Commit außerhalb der Dateibereinigung; Fehler nur `report()`. |
|
||||
| N09 (P2) | offen | Snapshot-Deduplizierung nur über Bildbytes, `put()`-Ergebnisse ungeprüft — **noch nicht umgesetzt** (siehe unten). |
|
||||
| N10 (P2) | bestätigt | `delete()`/`put()` ausgewertet; Tombstone erst nach bestätigter Löschung; `purgeDue()` liefert `{due, purged, failed}`; Export über `.tmp` + `move`; Commands enden mit FAILURE bei Fehlern (Scheduler-Alarm greift). |
|
||||
| N11 (P2) | bestätigt | `record()` schreibt `.tmp` → Zeile → `move`; Marker `press_releases.archive_pending_at` in der fachlichen Transaktion, `archive:retry-pending` (03:35) holt `pm_depublished`/`gdpr_change`/`image_removed` nach, `archive:sweep-orphans` (03:40) räumt Dateien ohne Zeile; Anonymisierung/Korrektur archivieren aus dem Redaction-Snapshot; Systemstatus zeigt offene Marker. `deleteFromAdmin` bleibt blockierend (E15). |
|
||||
| N12 (P2) | bestätigt | Anonymisierung entfernt Bilder nach dem Commit über `PressReleaseImageRemover` (`image_removed`, Grund `gdpr`, Antrag referenziert); lokale Beweisdateien danach weg, Pfade an der Zeile geleert. |
|
||||
| N13 (P2) | bestätigt (Lücke zu O1) | `press-releases:purge-drafts` erfasst zusätzlich `rejected` mit `published_ever_at` NULL: gleiche Frist ab letzter Änderung, nur Medien, Status bleibt (E12). Altbestand mit früherer Veröffentlichung unangetastet. |
|
||||
| N14 (P2) | bestätigt | Phase 2 je Kunde in Transaktion: Posten sperren, Marker per bedingtem UPDATE beanspruchen, Mail in derselben Transaktion einplanen (DB-Queue, E18). |
|
||||
| N15 (P2) | bestätigt | Kohorten halboffen `[lower, upper)`, lückenlos; Kohortensumme = Segment. Basiswert 0.1 bleibt mit Fußnote stehen. |
|
||||
| N16 (P2) | bestätigt | `byReader()` gruppiert nach Art, Schlüssel, Portal und Sprache wie `topFeeds()`. |
|
||||
| N17 (P2) | bestätigt | `sitemap_role` (`source`/`copy`/`none`) und `sitemap_portals` aus derselben Regel wie die Sitemaps; Kundenansicht mit drittem Zweig für Kopien. |
|
||||
| N18 (P2) | bestätigt | Nenner und Zustände auf derselben Menge (`visibleOn()`); jüngster Check über `max(id)`. |
|
||||
| N19 (P2) | bestätigt | `reassignCopiesOf()` bei Depublikation, Gone, Löschung und Admin-Statuswechsel; Erstquelle nur ohne Soft-Delete-Umgehung aufgelöst; Admin-Republish ordnet zu. |
|
||||
| N20 (P2) | bestätigt | Strikte Schemaprüfung im OpenAI-Treiber (Objekt je Kategorie, echtes Bool, endliche Konfidenz 0…1) → Zustand `error`; `normalize()` wertet nur `hit === true`. |
|
||||
| N21 (P2) | bestätigt | Marke ungecacht (`AppSetting::getValueFresh()`) in Aggregation und Purge; Cache im Konfliktfall verworfen; `setValue()` löscht den Cache erst nach Commit. |
|
||||
| N22 (P1) | bestätigt | Guard in `Tests\TestCase::setUpTraits()`, also vor `RefreshDatabase`; phpunit.xml pinnt die Feature-Flags. |
|
||||
| 5.1 a | bestätigt | Beim Tombstone eines `image_removed`-Eintrags werden Bestätigungen, Korrekturen und die weich gelöschte Bildzeile hart gelöscht (E13). |
|
||||
| 5.1 b | bestätigt | `label_corrected` nur für veröffentlichte Bilder (E14). |
|
||||
| 5.1 c | teilweise | Abgleich nach Restore läuft zusätzlich über alle DB-Tombstones; externes Exportziel nicht gebaut (E16), Runbook-Hinweis. |
|
||||
| 5.1 d | bestätigt | `archive_entries.legal_request_id`, Activity-Meta trägt `archive_entry_id`, Archivseite filtert nach Vorgang. |
|
||||
| 5.1 e | bestätigt | `App\Support\FileDeletion` (Ergebnis + `exists()`); nie veröffentlicht → Exception in der Transaktion, veröffentlicht → Log + Systemstatus-Zähler. |
|
||||
| 5.2 Kategorienfeed | bestätigt | Kategorie-Admin leert die Seiten-Caches bei Änderung von Sichtbarkeit, Portal, Eltern oder Slug. |
|
||||
| 5.2 Dry-Run | bestätigt | `purge-events --dry-run` zählt Crawler- und Feed-Zeilen mit. |
|
||||
| 5.2 übrige | offen | Synchroner Bildcheck (Zeitbudget), Dekodieraufwand, Report-Skalierung, OG-Cache bei Korrektur: Messung bzw. Betreiberentscheidung, nicht Teil dieser Nacharbeit. |
|
||||
| 5.3 | erledigt | Audit, Decision-Update und Plan Fassung 2 versioniert, Antwortkopie entfernt; U10-Formulierung präzisiert. Browser-/Tastaturabnahme und MySQL-/Worker-CI bleiben offen. |
|
||||
|
||||
### Live-Schritte für Block 8
|
||||
|
||||
1. `php artisan migrate --force` — zwei nullable Spalten (`archive_entries.legal_request_id`, `press_releases.archive_pending_at`), INSTANT, Sekunden.
|
||||
2. `php artisan schedule:list` — neu `archive:retry-pending` 03:35 und `archive:sweep-orphans` 03:40 (beide mit Alarm bei Fehlschlag).
|
||||
3. `php artisan press-releases:purge-drafts --dry-run` — vor dem ersten Wochenlauf prüfen, dass nur `rejected`-Meldungen **ohne** `published_ever_at` erfasst werden (10.463 „offline genommen"-Altfälle müssen draußen bleiben).
|
||||
4. `php artisan archive:retry-pending --dry-run` und `archive:sweep-orphans --dry-run` einmal ansehen; Systemstatus zeigt offene Marker und lokale Beweisreste.
|
||||
5. `view:cache`, `config:cache`, `queue:restart`, FPM-Neustart wie üblich.
|
||||
|
||||
**Nicht in dieser Nacharbeit:** N09 (Snapshot-Versionierung nach Credit-/KI-Korrektur und `put()`-Prüfung im Snapshot) — eigener Schritt, weil die Snapshot-Datei damit versioniert werden muss (Bildbytes plus Metadaten) und der Neuaufbau bei Korrektur mit der OG-Cache-Frage (5.2) zusammenhängt.
|
||||
|
||||
## Nicht aufgenommen
|
||||
|
||||
- **F21 Legacy-Import.** Befund korrekt (Vollladen der Pivot-Tabellen, kein Transaktionsschutz, Wiederanlauf ändert UUID und Slug). Der Importer läuft seit dem 16.07. nicht mehr und ist nicht im Scheduler. Falls das Altsystem noch einmal einen Delta-Lauf braucht: `importRow()` in `DB::transaction` und vorhandene PM über `(legacy_portal, legacy_id)` statt über die Importmap erkennen. Bis dahin steht nur diese Notiz.
|
||||
|
|
@ -280,6 +330,20 @@ Am 18.09.2026 alle sechs nach Empfehlung entschieden. Umsetzung ab demselben Tag
|
|||
| E8 | U09: ungenutzte Fortify-2FA-Verwaltungsrouten | abschalten, folgt aus E3 |
|
||||
| E9 | U05–U07: Newsletter-Wiederaufnahme und Doppelversand | aufgeschoben, bis das Kampagnenmodul in Betrieb geht; bis dahin nur Abmeldung und Sperrliste live (Nutzer, 18.09.2026) |
|
||||
|
||||
Entscheidungen aus Block 8 (25.09.2026, vorläufig getroffen bei der Umsetzung — der Betreiber bestätigt oder korrigiert):
|
||||
|
||||
| Nr. | Frage | Entscheidung |
|
||||
|---|---|---|
|
||||
| E10 | N05: Wer darf die Kundenbestätigung eines Admin-Uploads abgeben? | nur der Kontoinhaber der Meldung (`press_releases.user_id`), keine Teammitglieder, kein Super-Admin — er ist der Vertragspartner (DU E1) |
|
||||
| E11 | N03: Altbestand an Klassifikationen ohne Audit-Hash | keine Regel „ohne Audit-Hash kein Auto-Publish"; alle 3.387 Alt-Audits haben keinen Hash, die Transaktion schließt das Fenster |
|
||||
| E12 | N13: abgelehnte, nie veröffentlichte Einreichungen | Medien nach derselben Frist wie Entwürfe (180 Tage ab letzter Änderung), Status bleibt `rejected` (Vertragsdokumentation nach DU 4.1), früher veröffentlichter Altbestand unangetastet |
|
||||
| E13 | 5.1 a: Kopien außerhalb des Archivs | Bestätigungs- und Korrekturzeilen sowie die weich gelöschte Bildzeile werden mit dem Archiv-Tombstone hart gelöscht (E-B10, DSE 9a) |
|
||||
| E14 | 5.1 b: Korrektur eines nie veröffentlichten Bildes | kein Archiveintrag; die Korrekturzeile dokumentiert, das Manifest beim späteren `image_removed` enthält alle Korrekturen |
|
||||
| E15 | N11: Archivausfall bei Löschung/Anonymisierung | blockiert nicht (Art. 12 Abs. 5 DSGVO), Marker + täglicher Nachholer; nur `deleteFromAdmin` bleibt blockierend |
|
||||
| E16 | 5.1 c: Tombstone-Export bei vollständigem Disk-Restore | externes Ziel nicht gebaut; Runbook verlangt, den aktuellen Export vor dem Abgleich einzuspielen — Betreiber entscheidet über Storage Box/S3 |
|
||||
| E17 | N01: Cache-Lebensdauer öffentlicher Medien (24 h) | unverändert; ein zurückgehaltenes Bild verschwindet für neue Abrufe sofort, Browser-/CDN-Kopien laufen aus |
|
||||
| E18 | N14: Idempotenz der Ablaufmail | Transaktion setzt die DB-Queue voraus (`QUEUE_CONNECTION=database`, kein eigenes `DB_QUEUE_CONNECTION`); bei Wechsel auf Redis Zwei-Spalten-Claim nötig |
|
||||
|
||||
## Umsetzungsprotokoll
|
||||
|
||||
| Datum | Punkte | Commit | Bemerkung |
|
||||
|
|
@ -295,8 +359,12 @@ Am 18.09.2026 alle sechs nach Empfehlung entschieden. Umsetzung ab demselben Tag
|
|||
| 18.09.2026 | 7.1, 7.5, 7.6, 7.8–7.12 | `235d392` | Fortify-2FA-Routen 404, Policy-Kurzschluss nur aktiv, API-Portalwechsel prüft Kategorie, Aggregation mit Zeitbudget und gesperrter Marke, Bereinigung behält `sent`, Sync nach E-Mail-Wechsel, `--classify` mit Vorschau und `--before`, Detailseite sortiert wie Resolver, Protokoll korrigiert |
|
||||
| 18.09.2026 | 7.7 | `1cd9fd1` | Vertragsablauf: bedingtes Beenden unter Sperre, Marker, Mail nachholbar mit FAILURE-Exit |
|
||||
| 18.09.2026 | 7.2, 7.3, 7.4 | `ea68362` | Bedingtes UPDATE in beiden Jobs, Prüfung im Publish-Lock für `ki`/`scheduler`, `StaleClassificationException`; roter Re-Check einer Review-PM lehnt ab (gilt auch für den Admin-Re-Check, PMs mit `manual_review_required_at` ausgenommen); NULL-Periode = laufender Monat plus Backfill |
|
||||
| 25.09.2026 | Block 8: N22, N06 (Gate), 5.3 | `4e34c3d` | Guard in `setUpTraits()`, Flags in phpunit.xml gepinnt, Zustimmung an gezeigte Fassung gebunden, Audit/Decision-Update/Plan versioniert |
|
||||
| 25.09.2026 | Block 8: N01–N05, N07, N08, N10–N21, 5.1 a–e, 5.2 | `48129e9` | vier parallel geprüfte und umgesetzte Gruppen (Bilder, Archiv, KI/Hintergrund, Berichte); zwei Migrationen; 12 + 9 + 7 + 8 neue Tests |
|
||||
|
||||
Gesamtsuite nach Block 7: 1.930 Tests grün, einer übersprungen; PHPStan ohne Meldung; Pint sauber. Ein Test (`ApiPortalResolutionTest`) brauchte wegen der neuen Kategorieprüfung eine gemeinsame Kategorie statt einer zufälligen.
|
||||
Gesamtsuite nach Block 7: 1.930 Tests grün, einer übersprungen; PHPStan ohne Meldung; Pint sauber.
|
||||
|
||||
Gesamtsuite nach Block 8 (25.09.2026, HEAD `48129e9`, Befehl `php artisan test --compact` nach `config:clear`): 2.122 Tests grün, einer übersprungen; Larastan Level 4 ohne Meldung auf allen geänderten Dateien; Pint sauber. Offen: N09, Browser-/Tastaturabnahme, MySQL-/Worker-CI, die Messpunkte aus 5.2. Ein Test (`ApiPortalResolutionTest`) brauchte wegen der neuen Kategorieprüfung eine gemeinsame Kategorie statt einer zufälligen.
|
||||
|
||||
Offen: U05–U07 nach E9 aufgeschoben; 7.6 (Fokusführung) manuell im Browser abnehmen.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue