Optionaler eventSource-Block (url + crawlIntervalHours) im Venue-YAML. import-venues legt daraus idempotent eine inaktive scope='venue'-Source an (deterministische ID es_yaml_<slug>) — Re-Import lässt active + Crawl-State (failCount/Backoff) unangetastet, Reviewer-Aktivierung bleibt also erhalten. Strategie: venue-direkt zuerst (eigene Programmseiten, §87a-unkritisch, self-hostbar), stadtweite Guidle-Discovery als bewusste 2. Phase. Seed: 3 verifizierte Programm-URLs (zebra-kino /monatsprogramm, kula /program, kult-x kultur.kult-x.ch). Aktivierung bleibt Reviewer-Stop (probe -> active:true), wartet auf Service-Key (α-1c). Doku in CURATOR.md + STATUS.md (α-3.7). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
180 lines
6.9 KiB
Markdown
180 lines
6.9 KiB
Markdown
# Curator-Workflow — Seepuls
|
||
|
||
Wie Inhalte in den Seepuls-Korpus kommen. Drei Skills, klare Reviewer-
|
||
Stops, dieselbe Disziplin wie bei Cardecky und Zitare.
|
||
|
||
> Cross-Repo-Pattern: [`../mana/docs/CONTENT_PIPELINES.md`](../../mana/docs/CONTENT_PIPELINES.md)
|
||
> ist die Single-Source-of-Truth für Pipeline-Patterns. Seepuls folgt
|
||
> dem dort dokumentierten 5-Stufen-Skelett (Plan → Recherche → Design
|
||
> → Validate → Publish) mit Reviewer-Stops nach Plan und Design.
|
||
|
||
## Drei Skills
|
||
|
||
| Skill | Aufgabe | SOT |
|
||
|---|---|---|
|
||
| [`/seepuls-curate-venue`](../.claude/skills/seepuls-curate-venue.md) | Venue anlegen oder erweitern | YAML in `apps/api/src/data/curated/venues/<slug>.yml` |
|
||
| [`/seepuls-validate-venue`](../.claude/skills/seepuls-validate-venue.md) | Read-only-Check eines Draft-Venue (7 Findings) | — |
|
||
| [`/seepuls-curate-events`](../.claude/skills/seepuls-curate-events.md) | Events einer Venue pflegen (Crawl-Mode + Manual-Mode) | DB direkt (`seepuls.events`) |
|
||
|
||
## SOT-Wahl: warum Venues YAML, Events DB?
|
||
|
||
| Aspekt | Venues | Events |
|
||
|---|---|---|
|
||
| Lebenszeit | langlebig, ändern sich selten | kurzlebig (verschwinden nach Datum) |
|
||
| Volumen | 30–80 realistisch | 500–5000 |
|
||
| Audit-Trail | git-getracktes YAML wertvoll | DB-`crawl_jobs` reicht |
|
||
| Re-Import | idempotent, ersetzt manuelle Korrekturen | Dedupe-Upsert via `external_id_hash` |
|
||
| Curator-Disziplin | jeder Eintrag will durchdacht sein | Bulk-Streams, automatisch |
|
||
|
||
Venues sind die wenigen handgepflegten Anker; Events fließen daran
|
||
vorbei.
|
||
|
||
## Workspace-Disziplin
|
||
|
||
Drafts leben **außerhalb des Repos** in `~/Documents/seepuls-drafts/<slug>/`:
|
||
|
||
```
|
||
~/Documents/seepuls-drafts/
|
||
├─ museum-rosenegg/ ← venue-draft
|
||
│ ├─ plan.md
|
||
│ ├─ research/{sources,notes}.md
|
||
│ ├─ design/venue.yml
|
||
│ ├─ validate/report.md
|
||
│ └─ publish/import.log
|
||
└─ museum-rosenegg-events-2026-06-15/ ← events-draft (datum-gestempelt)
|
||
├─ plan.md
|
||
├─ research/probe.json
|
||
├─ design/events.jsonl
|
||
├─ validate/report.md
|
||
└─ publish/run.log
|
||
```
|
||
|
||
Vorteil: Audit-Trail bleibt, ohne den Repo aufzublähen. Re-Run nach
|
||
Unterbrechung möglich.
|
||
|
||
## Pflicht-Reviewer-Stops
|
||
|
||
Auch wenn der User „mach einfach" gesagt hat:
|
||
|
||
1. **Nach Plan-Stufe** — Boundaries festklopfen, Slug bestätigen,
|
||
Modus festlegen.
|
||
2. **Nach Design-Stufe** — strukturierte Daten (YAML oder JSONL) als
|
||
Markdown-Preview, ja/nein.
|
||
3. **Vor Publish** — Compliance-Veto durch `mana-compliance`-Subagent
|
||
bei sensiblen Inhalten.
|
||
|
||
Stops sind kurz und retten den Korpus vor Müll. Bei Bulk-Operationen
|
||
reicht Sampling-Stop (5–10 zufällige Einträge + Streitfall-Liste).
|
||
|
||
## Lizenz und Attribution
|
||
|
||
**Venues und Events sind keine kreativen Schöpfungen** — wir aggregieren
|
||
öffentliche Veranstaltungs-Daten Dritter. Die Felder folgen daher der
|
||
Aggregator-Policy, nicht der CC-Lizenz-Logik von Zitare oder Cardecky:
|
||
|
||
- `attributionRequired: true` ist Default (sichtbare Quell-Domain im
|
||
Frontend).
|
||
- `source.url` + `source.refs[]` sind Pflicht für Audit + Take-Down.
|
||
- Bilder via Hot-Link (siehe `mana/docs/AGGREGATOR_POLICY.md` §3).
|
||
- Lebende Personen (Künstler:innen einer Veranstaltung) werden nur
|
||
als Title-String erfasst, keine Personen-Profile.
|
||
|
||
Volle Policy: [`../mana/docs/AGGREGATOR_POLICY.md`](../../mana/docs/AGGREGATOR_POLICY.md).
|
||
|
||
## Importer-Workflow
|
||
|
||
```bash
|
||
# Venue-YAML editieren oder via Skill anlegen, dann:
|
||
pnpm --filter ./apps/api db:import-venues
|
||
|
||
# Output: "X inserted, Y updated, 0 errors"
|
||
# Idempotent: zweiter Run = 0 inserted, X+Y updated
|
||
```
|
||
|
||
Bei Schema-Validierungs-Fehlern bricht der Importer mit exit 1 ab.
|
||
Das YAML muss korrigiert werden, kein Auto-Fix.
|
||
|
||
### Event-Source einer Venue mit-kuratieren
|
||
|
||
Optionaler Block im Venue-YAML — die eigene Event-/Programm-Seite der
|
||
Venue (NICHT ein stadtweiter Sammelkalender, das ist `scope='city'` per
|
||
Admin-API):
|
||
|
||
```yaml
|
||
eventSource:
|
||
url: 'https://zebra-kino.de/monatsprogramm/'
|
||
# crawlIntervalHours: 24 # optional, 6..168, Default 24
|
||
```
|
||
|
||
Der Importer legt daraus idempotent eine `scope='venue'`-Source an
|
||
(deterministische ID `es_yaml_<slug>`), **inaktiv**. Re-Import
|
||
aktualisiert URL/Intervall, lässt aber `active` und den Crawl-State
|
||
(failCount/Backoff) unangetastet — eine vom Reviewer freigegebene Source
|
||
wird nicht zurückgesetzt.
|
||
|
||
Aktivierung bleibt manueller Reviewer-Stop (AGGREGATOR_POLICY):
|
||
|
||
```
|
||
POST /api/v1/admin/event-sources/<id>/probe # Vorschau, kein DB-Write
|
||
PATCH /api/v1/admin/event-sources/<id> # { "active": true }
|
||
```
|
||
|
||
robots.txt + Crawl-Delay des Event-Source-Hosts prüft die Pipeline zur
|
||
Probe-/Crawl-Zeit automatisch.
|
||
|
||
## Anti-Halluzinations-Regeln (kompakt)
|
||
|
||
- **Niemals Adressen oder Koordinaten raten** — Nominatim oder
|
||
Quellen-Beleg.
|
||
- **Niemals Description LLM-paraphrasieren** — direkte Übernahme aus
|
||
offizieller Quelle, ≤ 200 Zeichen.
|
||
- **Niemals Social-URLs erfinden** — leer lassen wenn nicht auf der
|
||
Website verlinkt.
|
||
- **Niemals Datum aus Free-Form raten** — strict-ISO oder droppen.
|
||
- **Niemals Event ohne `starts_at`** — kein Datum, kein Event.
|
||
|
||
## Bulk-Mode
|
||
|
||
Erst ab größeren Mengen relevant:
|
||
|
||
- Venues: ≥ 10 auf einmal (z.B. „alle Konstanzer Museen aus
|
||
konstanz.de/tourismus"). Sampling-Stop auf 5.
|
||
- Events: ≥ 30 auf einmal (z.B. ein Saison-Programm). Sampling-Stop auf
|
||
10 + alle Streitfälle (Datum unklar etc.).
|
||
|
||
## Verhältnis zur automatischen Crawl-Pipeline
|
||
|
||
Seepuls hat **zwei Wege**, eine Venue/Events anzulegen:
|
||
|
||
1. **Skill-Pfad** (manuell, dieser Workflow): `/seepuls-curate-venue`
|
||
→ YAML-SOT → Importer. Reviewer-Stops Pflicht.
|
||
2. **Crawl-Pfad** (automatisch): `POST /api/v1/admin/venues/from-url`
|
||
→ mana-research → mana-llm → DB-row mit `crawl_status='pending-review'`.
|
||
Reviewer löst die Pending-Review später per UI.
|
||
|
||
Beide schreiben in dieselbe `seepuls.venues`-Tabelle. `crawl_status`
|
||
unterscheidet (`manual-entry` vs `pending-review` vs `claimed`).
|
||
YAML-SOT existiert nur für `manual-entry`-Venues.
|
||
|
||
## Offene Punkte
|
||
|
||
- **Venues aus Crawl-Pfad nach YAML-SOT migrieren**: wenn ein
|
||
pending-review-Eintrag vom Reviewer akzeptiert wird, sollte er
|
||
optional ins YAML wandern (für git-getrackte Persistenz). Heute:
|
||
manueller Export aus DB.
|
||
- **Events-Validator-Skill** `/seepuls-validate-events` fehlt
|
||
(analog `/cards-validate-deck`).
|
||
- **Wikidata-Anbindung** für Venues — analog `/zitare-curate-author`
|
||
Wikidata-Enrich. V2.
|
||
- **mana-compliance-Subagent** muss für Venue/Event-Diffs sinnvolle
|
||
Veto-Heuristiken haben (Werte: keine kommerzielle Werbung, keine
|
||
Tracking-Wrapper, robots-Respect). Aktuell generischer Mission-Check.
|
||
|
||
## Referenzen
|
||
|
||
- Cross-Repo-Pattern: [`../mana/docs/CONTENT_PIPELINES.md`](../../mana/docs/CONTENT_PIPELINES.md)
|
||
- Aggregator-Policy: [`../mana/docs/AGGREGATOR_POLICY.md`](../../mana/docs/AGGREGATOR_POLICY.md)
|
||
- Skills: `.claude/skills/seepuls-curate-{venue,events}.md`,
|
||
`.claude/skills/seepuls-validate-venue.md`
|
||
- YAML-Format: `apps/api/src/data/curated/venues/README.md`
|
||
- Importer: `apps/api/src/jobs/import-venues.ts`
|