press-releases: assign-canonicals leert Seiten- und Sitemap-Caches; dev: Live-Lauf 21.09.2026 protokolliert (9.221 Paare)

Der Nachlauf über den Bestand änderte rel=canonical und die Sitemap-Auswahl,
ließ aber gecachte Meldungsseiten (1 h stale) und Sitemap-Caches (1 h)
stehen. Nach einem Lauf mit Änderungen wird WebCaches::forgetPublicPages()
aufgerufen; der Test prüft das über den vorher gecachten Sitemap-Stand.

Protokoll Teil 11: Nachtrag Live-Deploy (hash-content 179.619,
duplicates-report 9.221 Paare / 1.468 seit 07/2026, assign-canonicals
9.223/9.221, basiswert-0.1.json auf dem Server), Anhang 2 1c.7/1c.8 mit
Live-Zahlen, Basiswerte 0.1 mit Hinweis auf die noch zu holende Datei.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-09-21 13:05:43 +00:00
parent 2b042d6aa7
commit eb658020e5
5 changed files with 91 additions and 6 deletions

View file

@ -3,6 +3,7 @@
namespace App\Console\Commands; namespace App\Console\Commands;
use App\Services\PressRelease\CanonicalAssigner; use App\Services\PressRelease\CanonicalAssigner;
use App\Support\WebCaches;
use Illuminate\Console\Command; use Illuminate\Console\Command;
/** /**
@ -44,6 +45,14 @@ class AssignCanonicalPressReleases extends Command
$dryRun ? 'würden geändert' : 'geändert', $dryRun ? 'würden geändert' : 'geändert',
)); ));
// rel=canonical steckt in den gecachten Meldungsseiten, die Sitemaps
// (1 h) nennen nur die Erstquelle — nach einer Zuordnung über den
// Bestand sollen beide sofort den neuen Stand zeigen.
if (! $dryRun && $result['changed'] > 0) {
WebCaches::forgetPublicPages();
$this->line('Seiten- und Sitemap-Caches geleert.');
}
return self::SUCCESS; return self::SUCCESS;
} }
} }

View file

@ -68,6 +68,11 @@ erheben.
> nachgerüstet, aber die Zahlen oben stammen aus dem Lauf davor. Vor dem > nachgerüstet, aber die Zahlen oben stammen aus dem Lauf davor. Vor dem
> Livegang von Block 1 einmal nachziehen: > Livegang von Block 1 einmal nachziehen:
> `php artisan press-releases:view-distribution --json > basiswert-0.1.json` > `php artisan press-releases:view-distribution --json > basiswert-0.1.json`
>
> **21.09.2026:** Lauf mit `--from=2026-06-01 --to=2026-09-01 --json` auf
> dem Live-Server erfolgt, Datei liegt dort unter
> `dev/2026-09-01/basiswert-0.1.json`. Sobald sie im Repo ist, wird die
> Zeile „28–55 Tage" je Portal hier eingetragen.
--- ---

View file

@ -40,8 +40,8 @@ Schneller als über die API geht es zunächst über eine Bestandsabfrage nach id
| Nr. | Arbeitspaket | Aufwand | Abhängigkeit | | Nr. | Arbeitspaket | Aufwand | Abhängigkeit |
|---|---|---|---| |---|---|---|---|
| ~~1c.7~~ | Doppelveröffentlichung erheben — **gebaut 17.09.2026**: `content_hash`, `press-releases:hash-content`, `press-releases:duplicates-report`. Befund: 9.092 Paare = 53 % des Archivs (Protokoll Teil 9) | S | keine | | ~~1c.7~~ | Doppelveröffentlichung erheben — **gebaut 17.09.2026**: `content_hash`, `press-releases:hash-content`, `press-releases:duplicates-report`. Befund Dev: 9.092 Paare = 53 % des Archivs (Protokoll Teil 9); **Live 21.09.2026: 9.221 Paare = 18.442 URLs, 1.468 davon seit 07/2026** | S | keine |
| ~~1c.8~~ | Kanonische Zuordnung — **gebaut 17.09.2026, ausgeschaltet bis E9**: `CanonicalAssigner`, `canonical_press_release_id`, Zuordnung bei Veröffentlichung + `press-releases:assign-canonicals`; rel=canonical, mainEntityOfPage, Sitemaps nur Erstquelle. Schalter `CANONICAL_ASSIGNMENT_ENABLED` | M | 1c.7 | | ~~1c.8~~ | Kanonische Zuordnung — **gebaut 17.09.2026, seit E9 aktiv, Bestand live zugeordnet 21.09.2026 (9.221 Paare; Protokoll Teil 11, Nachtrag Live-Deploy)**: `CanonicalAssigner`, `canonical_press_release_id`, Zuordnung bei Veröffentlichung + `press-releases:assign-canonicals`; rel=canonical, mainEntityOfPage, Sitemaps nur Erstquelle. Schalter `CANONICAL_ASSIGNMENT_ENABLED` | M | 1c.7 |
| ~~1c.9~~ | Quellenauskunft — **gebaut 17.09.2026, hinter `GSC_CUSTOMER_VISIBLE`**: `user_canonical` gespeichert, `sourceVerdict()` (eigene / andere eigene Fassung / fremdes Portal), Text im Block „Google-Index" | S | 1c.4, 1c.8 | | ~~1c.9~~ | Quellenauskunft — **gebaut 17.09.2026, hinter `GSC_CUSTOMER_VISIBLE`**: `user_canonical` gespeichert, `sourceVerdict()` (eigene / andere eigene Fassung / fremdes Portal), Text im Block „Google-Index" | S | 1c.4, 1c.8 |
### Zur Auswahl in 1c.8 ### Zur Auswahl in 1c.8

View file

@ -2149,7 +2149,11 @@ Befunde und was daraus wurde:
Konversionsschritte; keine IP, lit. f) plus Frist 395 Tage in Abschnitt 13, Konversionsschritte; keine IP, lit. f) plus Frist 395 Tage in Abschnitt 13,
auf Hub und beiden Portalen (eine Datei). Text vom Betreiber abgenommen. auf Hub und beiden Portalen (eine Datei). Text vom Betreiber abgenommen.
- 0.1: Kohortenwerte „28–55 Tage" vom Live-System (Fenster 01.06.–01.09.) - 0.1: Kohortenwerte „28–55 Tage" vom Live-System (Fenster 01.06.–01.09.)
einmal erheben und ablegen: `php artisan press-releases:view-distribution --from=2026-06-01 --to=2026-09-01 --json > dev/2026-09-01/basiswert-0.1.json`. einmal erheben und ablegen: `php artisan press-releases:view-distribution --from=2026-06-01 --to=2026-09-01 --json > dev/2026-09-01/basiswert-0.1.json`
— **am 21.09.2026 auf dem Live-Server erzeugt**, liegt dort unter
`~/pressekonto.com/dev/2026-09-01/basiswert-0.1.json`; ins Repo
übernehmen und in `basiswerte-block0.md` eintragen (siehe Nachtrag
Live-Deploy unten).
- Abbruchbedingungen der Blöcke 1–3 tragen weiter Platzhalter für Zeitraum - Abbruchbedingungen der Blöcke 1–3 tragen weiter Platzhalter für Zeitraum
und Schwellwert; Block 1 läuft seit 17.09. ohne festen Vergleichspunkt. und Schwellwert; Block 1 läuft seit 17.09. ohne festen Vergleichspunkt.
- 2.2 Publisher Center (Betreiber), Ergebnis nach 4–6 Wochen in der Search - 2.2 Publisher Center (Betreiber), Ergebnis nach 4–6 Wochen in der Search
@ -2284,3 +2288,60 @@ Cache-Treffer, Report je Reader/Feed, Panel, Bereinigung),
`config:cache`. 0.7 (Datenschutzerklärung) ist seit dem 21.09.2026 erledigt, `config:cache`. 0.7 (Datenschutzerklärung) ist seit dem 21.09.2026 erledigt,
siehe oben. siehe oben.
### Nachtrag 21.09.2026 — Live-Deploy des Branches, Zuordnung über den Bestand
Der Branch `technik/betriebsfixes-2026-09` (Block 1c/1d-Reste, Block 2,
Anhang 1, Anhang 2, E9/E10, 3.1 mit Newsroom-Feeds, RSS-Seite und
Abruf-Protokoll, 0.7, Audit-Blöcke 1–7) ist am 21.09.2026 auf dem
Live-Server. Läufe nach der Migration, in dieser Reihenfolge:
| Schritt | Ergebnis |
|---|---|
| `press-releases:hash-content` | 179.619 Meldungen geprüft, 179.619 Prüfsummen ergänzt (ganzer Bestand inkl. Altbestand offline) |
| `press-releases:duplicates-report` (13:19) | sichtbar: presseecho 12.753, businessportal24 22.181, both 0; **9.221 Paare = 18.442 URLs**, davon 1.468 Paare seit 07/2026; Zuordnung vorher 0; keine Meldung ohne Prüfsumme |
| `press-releases:assign-canonicals --dry-run` | 9.221 Paare, 9.221 würden geändert |
| `press-releases:assign-canonicals` | **9.223 Paare, 9.221 geändert** |
| `press-releases:view-distribution --from=2026-06-01 --to=2026-09-01 --json` | `basiswert-0.1.json` auf dem Server geschrieben (0.1, siehe oben) |
Lesart der Zahlen:
- Live liegen 129 Paare mehr als auf der Dev-Kopie vom 17.09. (9.092) —
die Kopie war älter, seither sind neue Doppelveröffentlichungen
dazugekommen. 1.468 Paare seit Juli bei rund 2.900 Meldungen im
Quartal heißt: **etwa jede zweite neue Meldung erscheint auf beiden
Portalen.** Das ist der Befund aus Anhang 2, jetzt am Bestand belegt.
- Zwischen Dry-Run und scharfem Lauf kamen zwei Paare dazu (9.221 → 9.223),
die der Lauf **nicht** mehr ändern musste: die Zuordnung bei
Veröffentlichung (`CanonicalAssigner::assignFor`) hatte sie bereits
gesetzt. Damit ist der laufende Mechanismus live nachgewiesen, nicht nur
der Nachlauf über den Bestand.
- Erstquelle je Hauptkategorie wie in E9 konfiguriert: sonstiges (3.126
Paare), politik, haus, reisen, kultur, sport, mode, medizin → presseecho;
it (1.214), handel, motor-verkehr, finanzen, wissenschaft-forschung,
recht → businessportal24. Größter Einzelposten ist `sonstiges` — ein
Drittel aller Paare hat keine fachliche Zuordnung; das ist eher ein
Klassifikations- als ein Kanonisierungsthema.
- Die Sitemaps beider Portale tragen ab jetzt je Paar nur noch die
Erstquelle, die Kopie verweist per rel=canonical dorthin. In der Search
Console zeigt sich das über die nächsten Wochen als Rückgang bei
„Duplikat — Google hat eine andere Seite als kanonisch gewählt" bzw.
„Duplikat — vom Nutzer als kanonisch festgelegt" (1c.5/E8 lesen das aus
`press-releases:check-index-status` ab).
**Befund aus der Prüfung des Laufs, behoben:** `assign-canonicals` hat die
gecachten Meldungsseiten (rel=canonical, 5 min frisch / 1 h stale) und die
Sitemap-Caches (1 h) nicht geleert — nach dem Nachlauf über den Bestand
zeigten beide bis zu einer Stunde den alten Stand. Der Befehl ruft jetzt
nach einem Lauf mit Änderungen `WebCaches::forgetPublicPages()` auf und
meldet „Seiten- und Sitemap-Caches geleert." (`CanonicalAssignmentTest`
prüft das über den vorher gecachten Sitemap-Stand). Für den Live-Lauf vom
21.09. ist das inzwischen durch die TTL erledigt.
**Noch zu prüfen auf dem Server** (nicht Teil der Ausgabe oben):
`FEED_FETCHES_RECORDED_SINCE=2026-09-21` und
`CRAWLER_HITS_RECORDED_SINCE=2026-09-21` in der `.env` + `config:cache`;
`categories:seed-descriptions` (2.3); `livewire:publish --assets`;
`queue:restart` und FPM-Neustart; Audit-Plan „Live-Schritte nach dem
Deploy" (`company-memberships:audit`, `--classify --before=<Deploy-Zeitpunkt>`,
`schedule:list` auf `billing:expire-grandfathering`); Rechnungs-Paket
`legacy:settle-unpaid --dry-run` → scharf.

View file

@ -84,18 +84,28 @@ test('assigning the backlog links the duplicate to the source and the sitemaps l
[$pe, $b24] = duplicatePair('it'); [$pe, $b24] = duplicatePair('it');
// Vor der Zuordnung nennt jedes Portal seine eigene Fassung — und cached die Sitemap eine Stunde.
$this->get('https://presseecho.test/sitemap.xml')->assertSuccessful()
->assertSee('https://presseecho.test/de/press-release/doppel-standort', false);
$this->artisan(AssignCanonicalPressReleases::class, ['--dry-run' => true]) $this->artisan(AssignCanonicalPressReleases::class, ['--dry-run' => true])
->expectsOutputToContain('[Dry-Run] 1 Paare, 1 würden geändert.') ->expectsOutputToContain('[Dry-Run] 1 Paare, 1 würden geändert.')
->assertSuccessful(); ->assertSuccessful();
expect($b24->fresh()->canonical_press_release_id)->toBeNull(); expect($b24->fresh()->canonical_press_release_id)->toBeNull();
$this->artisan(AssignCanonicalPressReleases::class)->expectsOutputToContain('1 Paare, 1 geändert.')->assertSuccessful(); $this->artisan(AssignCanonicalPressReleases::class)
->expectsOutputToContain('1 Paare, 1 geändert.')
->expectsOutputToContain('Seiten- und Sitemap-Caches geleert.')
->assertSuccessful();
expect($pe->fresh()->canonical_press_release_id)->toBe($b24->id) expect($pe->fresh()->canonical_press_release_id)->toBe($b24->id)
->and($b24->fresh()->canonical_press_release_id)->toBeNull(); ->and($b24->fresh()->canonical_press_release_id)->toBeNull();
// Zweiter Lauf ändert nichts mehr. // Zweiter Lauf ändert nichts mehr.
$this->artisan(AssignCanonicalPressReleases::class)->expectsOutputToContain('1 Paare, 0 geändert.')->assertSuccessful(); $this->artisan(AssignCanonicalPressReleases::class)
->expectsOutputToContain('1 Paare, 0 geändert.')
->doesntExpectOutputToContain('Caches geleert')
->assertSuccessful();
// Detailseite: die Kopie zeigt per rel=canonical auf die Erstquelle, die Erstquelle auf sich selbst. // Detailseite: die Kopie zeigt per rel=canonical auf die Erstquelle, die Erstquelle auf sich selbst.
$this->get('https://presseecho.test/de/press-release/doppel-standort')->assertSuccessful() $this->get('https://presseecho.test/de/press-release/doppel-standort')->assertSuccessful()
@ -104,7 +114,7 @@ test('assigning the backlog links the duplicate to the source and the sitemaps l
$this->get('https://businessportal24.test/de/press-release/doppel-standort')->assertSuccessful() $this->get('https://businessportal24.test/de/press-release/doppel-standort')->assertSuccessful()
->assertSee('<link rel="canonical" href="https://businessportal24.test/de/press-release/doppel-standort">', false); ->assertSee('<link rel="canonical" href="https://businessportal24.test/de/press-release/doppel-standort">', false);
// Sitemaps: nur die Erstquelle. // Sitemaps: nur die Erstquelle — der Lauf hat den 1-h-Cache von oben geleert.
$this->get('https://presseecho.test/sitemap.xml')->assertSuccessful() $this->get('https://presseecho.test/sitemap.xml')->assertSuccessful()
->assertDontSee('https://presseecho.test/de/press-release/doppel-standort', false); ->assertDontSee('https://presseecho.test/de/press-release/doppel-standort', false);
$this->get('https://businessportal24.test/sitemap.xml')->assertSuccessful() $this->get('https://businessportal24.test/sitemap.xml')->assertSuccessful()