Some checks are pending
CI / validate (push) Waiting to run
Drei Skills + Importer + Migration der 5 existierenden Venues.
Skills (alle repo-lokal in .claude/skills/):
- seepuls-curate-venue: 5-Stufen-Pipeline (Plan → Recherche → Design
→ Validate → Publish), Reviewer-Stops Pflicht, Nominatim-Geocoding
mit Politeness, YAML als Output. Bulk-Mode für >10 Venues.
- seepuls-validate-venue: read-only, 8 Checks (slug-unique,
country-enum, region-enum, coords-plausibel, description-länge,
robots-allow, source-coverage, enum-fit).
- seepuls-curate-events: zwei Modi (Crawl via admin-API mit
Service-Key, oder Manual aus User-Input). DB-as-SOT (nicht YAML),
weil Events kurzlebig sind.
Importer:
- apps/api/src/jobs/import-venues.ts: liest curated/venues/*.yml,
upsert in seepuls.venues, idempotent (zweiter Run = 0 inserted,
N updated). Zod-Validation der YAML-Form.
- pnpm db:import-venues script.
- Pattern an zitare-Importer orientiert.
SOT-Migration der 5 bestehenden Venues:
- apps/api/src/data/curated/venues/{museum-rosenegg,
seemuseum-kreuzlingen, bodensee-planetarium-kreuzlingen,
rosgartenmuseum, archaeologisches-landesmuseum-konstanz}.yml
- README.md mit Format-Doku.
Doku:
- seepuls/docs/CURATOR.md: Workflow-Übersicht, verweist auf
mana/docs/CONTENT_PIPELINES.md als Cross-Repo-Pattern.
Lokal validiert (gegen Postgres :5441):
- 1. Lauf: 5 inserted ✓
- 2. Lauf: 0 inserted, 5 updated ✓ (idempotent)
- type-check + 43/43 Tests grün.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
168 lines
5.2 KiB
Markdown
168 lines
5.2 KiB
Markdown
---
|
|
name: seepuls-validate-venue
|
|
description: Validiert ein seepuls-curate-venue-Draft (slug-unique, country-enum, region-enum, coords-plausibel, description-länge, robots-allow, source-coverage) bevor er ins curated/venues/ landet. Read-only, produziert validate/report.md.
|
|
argument-hint: '<venue-slug>'
|
|
allowed-tools:
|
|
- Read
|
|
- Write
|
|
- Edit
|
|
- Bash(ls *)
|
|
- Bash(grep *)
|
|
- Bash(cat *)
|
|
- Bash(curl *)
|
|
- Bash(jq *)
|
|
- Bash(docker exec *)
|
|
---
|
|
|
|
# `/seepuls-validate-venue` — QA für ein Draft-Venue
|
|
|
|
Vorletzte Stufe der `/seepuls-curate-venue`-Pipeline. Liest
|
|
`~/Documents/seepuls-drafts/<slug>/design/venue.yml` und produziert
|
|
`<slug>/validate/report.md` mit allen Findings.
|
|
|
|
Schwester-Skill von `/cards-validate-deck` (Cardecky-Spaced-Repetition)
|
|
und der inline-Validate-Stage in `/zitare-curate-quote`.
|
|
|
|
## Wann benutzen
|
|
|
|
- Direkt nach Stage 3 von `/seepuls-curate-venue` (venue.yml steht).
|
|
- Vor dem Publish (Stage 5). Bei rotem Report: **nicht eigenmächtig
|
|
fixen**, sondern dem User die Findings melden + welche Stufe nochmal.
|
|
|
|
## Inputs
|
|
|
|
1. **Draft-Slug** (Pflicht) — z.B. `museum-rosenegg`.
|
|
|
|
## Checks
|
|
|
|
### 1. slug-unique
|
|
|
|
Slug ist neu im Korpus:
|
|
```bash
|
|
ls seepuls/apps/api/src/data/curated/venues/<slug>.yml 2>/dev/null
|
|
docker exec seepuls-postgres psql -U seepuls -d seepuls -tAc \
|
|
"SELECT slug FROM seepuls.venues WHERE slug='<slug>'"
|
|
```
|
|
Treffer → **rot**. Vorschlag: `<slug>-<stadt>` oder `<slug>-2`.
|
|
|
|
**Exception:** Wenn der User explizit ergänzen will (`--slug
|
|
<existing>` in curate-venue), nur Warning, kein rot.
|
|
|
|
### 2. country-enum
|
|
|
|
`countryCode ∈ {DE, CH, AT, LI}`. Treffer-Miss → **rot**.
|
|
|
|
### 3. region-enum
|
|
|
|
`regionSlug ∈ {bodensee, hegau, thurgau-west, oberschwaben}` ODER
|
|
fehlt komplett (null). Andere Werte → **rot** (Region erst seed-en).
|
|
|
|
### 4. coords-plausibel
|
|
|
|
`coordinates.lat ∈ [47.4, 47.9]` UND `coordinates.lng ∈ [8.5, 9.7]`
|
|
(Bodensee-Bounding-Box). Außerhalb → **rot**, vermutlich falscher
|
|
Geocode oder falsche Region.
|
|
|
|
Plus: Cross-Check `countryCode`:
|
|
- DE-Venue mit lat < 47.55 (Schweizer Seeufer) → Warning.
|
|
- CH-Venue mit lat > 47.66 (deutsches Ufer) → Warning.
|
|
|
|
### 5. description-länge
|
|
|
|
`description.length` ∈ [10, 220]:
|
|
- < 10 → **rot**, zu kurz für sinnvolle Anzeige.
|
|
- > 220 → **rot**, AGGREGATOR_POLICY §2 verlangt ≤ 200 (mit kleinem
|
|
Puffer auf 220 für UTF-8-Zähl-Diff).
|
|
|
|
### 6. robots-allow
|
|
|
|
`source.url`-Domain erlaubt das Crawlen seepuls-Bot:
|
|
```bash
|
|
curl -sf -H "User-Agent: seepuls/0.0.1 (+https://seepuls.mana.how; kontakt@mana.how)" \
|
|
--max-time 5 "https://<domain>/robots.txt" | head -40
|
|
```
|
|
Manuelles Checken: gibt es `Disallow: /` für `*` oder für `seepuls`?
|
|
→ **rot**, Eintrag nicht anlegen. Domain in `blocked_domains` tragen.
|
|
|
|
Wenn `robots.txt` 404 oder timeout: **warnung** (default-allow), aber
|
|
flaggen.
|
|
|
|
### 7. source-coverage
|
|
|
|
`source.refs[]` enthält ≥ 1 Eintrag, jeder ≥ 3 Zeichen. Leerer Array
|
|
→ **rot**, Curator hat keine Quelle dokumentiert.
|
|
|
|
`source.url` und `source.domain` müssen übereinstimmen:
|
|
```bash
|
|
echo '<source.url>' | sed -E 's|^https?://([^/]+).*|\1|' | tr 'A-Z' 'a-z'
|
|
```
|
|
Sollte gleich `source.domain` sein (modulo www-Stripping). Sonst **rot**.
|
|
|
|
### 8. enum-fit (`crawlStatus`)
|
|
|
|
`crawlStatus ∈ {manual-entry, pending-review, claimed}`. Andere Werte
|
|
→ **rot**, sonst greift der Importer (oder spätere Constraints).
|
|
|
|
## Output
|
|
|
|
`~/Documents/seepuls-drafts/<slug>/validate/report.md`:
|
|
|
|
```
|
|
# Validate-Report — <slug>
|
|
|
|
Draft-Path: <…>
|
|
Geprüft: 2026-MM-DD HH:MM
|
|
|
|
## Findings
|
|
|
|
✓ slug-unique: neu (kein YAML, keine DB-Row)
|
|
✓ country-enum: CH
|
|
✓ region-enum: bodensee
|
|
✓ coords-plausibel: 47.6442, 9.1720 — im Bodensee-BBOX
|
|
✓ description-länge: 137 Zeichen
|
|
✓ robots-allow: robots.txt erlaubt /
|
|
✓ source-coverage: 2 refs
|
|
✓ enum-fit: crawlStatus=manual-entry ok
|
|
|
|
## Empfehlung
|
|
|
|
Grün — bereit für Publish (Stage 5).
|
|
```
|
|
|
|
Bei roten Findings:
|
|
|
|
```
|
|
✘ coords-plausibel: 47.123, 9.456 — Lat zu südlich, außerhalb Bodensee-BBOX
|
|
✘ description-länge: 245 Zeichen (Limit 220)
|
|
|
|
## Empfehlung
|
|
|
|
Stop vor Publish. Nochmal Stufe 3:
|
|
- Adresse re-geocoden — vielleicht falsche Stadt erwischt.
|
|
- Description am Satz-Ende kürzen, nicht umformulieren.
|
|
```
|
|
|
|
## Was dieser Skill NICHT macht
|
|
|
|
- **Eigenmächtig fixen.** Findings → User entscheidet.
|
|
- **YAML schreiben oder editieren.** Read-only.
|
|
- **DB-State ändern.** Read-only.
|
|
- **Robots-Tiefen-Parse.** Heuristik: `Disallow: /` für `*` oder
|
|
`seepuls`. Komplexe Path-Patterns → User soll manuell checken.
|
|
|
|
## Offene Punkte
|
|
|
|
- **Robots-Lookup könnte in `src/crawl/robots.ts` der API wiederverwendet
|
|
werden.** Aktuell ist der Validator-Skill bash-only — der echte Parser
|
|
(mit Cache + Path-Match) lebt in Bun-Code. Bei systematischen
|
|
False-Positives: Validator als `bun script` mit Import aus
|
|
`apps/api/src/crawl/robots.ts` umbauen.
|
|
- **Geographische Region-Inference.** Bei klar falschem Region-Slug
|
|
(z.B. „Friedrichshafen" mit `regionSlug: thurgau-west`) wäre eine
|
|
Vorschlag-Heuristik nett. Heute: Warning, kein Auto-Fix.
|
|
|
|
## Referenzen
|
|
|
|
- Schwester-Skill: `/seepuls-curate-venue`
|
|
- Cross-Repo-Pattern: `/cards-validate-deck`
|
|
- Aggregator-Policy: `../mana/docs/AGGREGATOR_POLICY.md`
|