一键导入
data-pipeline-ops
Load when adding/editing race profiles, running enrichment, scraping, or regenerating the site from data.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Load when adding/editing race profiles, running enrichment, scraping, or regenerating the site from data.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Load before any deploy to gravelgodcycling.com or any SiteGround/WordPress operation (push_wordpress.py, mu-plugin edits, cache purge, Elementor pages).
Load when touching race scores, ratings, rankings, testimonials, or any trust-bearing editorial claim.
Load when touching brand colors/fonts/tokens, CI workflows, or Python version/dependency issues.
Load when touching email capture, sequences, Mission Control, athlete replies, or any conversion surface.
Write, revise, or extend Gravel God / Roadie Labs email sequences (Mission Control drip emails, lifecycle triggers, broadcasts). Use whenever the task touches mission_control/templates/emails/, sequence definitions, subjects, or new email-marketing ideas for either brand. Encodes the Physiqonomics-derived voice models, the conversion principles, the hard constraints, and the ship process.
| name | data-pipeline-ops |
| description | Load when adding/editing race profiles, running enrichment, scraping, or regenerating the site from data. |
race-data/*.json (757 profiles, source of truth) → scripts/generate_index.py
builds web/race-index.json (757-entry search/filter index — verified count
matches) → wordpress/generate_neo_brutalist.py renders race pages into
output/ → scripts/push_wordpress.py tar+ssh deploys to SiteGround.
Regenerate the index after ANY profile edit, before regenerating pages — the search/filter UI and JSON-LD read the index, not the profiles directly, and a stale index silently ships old vitals/scores.
python scripts/generate_index.py --with-jsonld # index + per-race JSON-LD
python scripts/generate_index.py --stats # coverage check only
Race pages render from race-data/*.json (new format) via
wordpress/generate_neo_brutalist.py <slug> or --all. It also supports a
legacy data/*-data.json format — don't create new profiles in that format.
CLAUDE.md's HTML Generation section covers the load-bearing ones:
d['race']['gravel_god_rating'] path, _parse_score(), _safe_json_for_script().
Read that first. Additional traps verified against a live profile
(race-data/114-gravel-race.json):
gravel_god_rating holds 14 bare
integer scores + overall_score/tier. biased_opinion_ratings holds the
SAME 14 criteria as {score, explanation} objects in Matti voice.
batch_enrich.py writes biased_opinion_ratings only — it does not touch
gravel_god_rating. A generator reading one and not the other renders a
stale score next to a mismatched explanation.youtube_data, tire_recommendations,
citations, photos, history.notable_moments are absent or [] on
thinner profiles. Guard with .get() chains.rider_intel can exist with every field empty. search_text can be
full of prose explaining that NO usable intel was extracted (transcript was
music/foreign speech/fragmented). A non-empty search_text is not proof of
real intel — check key_challenges/terrain_notes arrays are non-empty too.curated: false videos stay in videos[]. Only curated: true entries
should render; the array holds accepted and rejected results side by side.history.founded / guide_variables.altitude_feet are null-typed, not
absent. Same falsiness risk as CLAUDE.md #4 (esc(0)) — check is None,
not truthiness, on any numeric vitals field here.skills/ dir (NOT
.claude/skills/): skills/RACE_RESEARCH_BRIEF_SKILL_UPDATED.md defines
source-diversity requirements and handoff format; skills/research_prompt.md,
skills/voice_guide.md back it. Prompt/doc system for a human-or-Claude
research pass, not an executable script.python scripts/batch_research.py --auto N → research-dumps/{slug}-raw.md
via Kimi K2 web search.python scripts/batch_enrich.py --slugs <slug>
reads the dump + existing profile, calls Claude for biased_opinion_ratings
explanations, merges into race-data/{slug}.json. Use --dry-run first.python scripts/validate_race_data.py cross-checks vitals
against known_races.py / athletes/config/races.json in the sibling
training-plan-pipeline repo, catches gain-vs-ASL copy-paste errors and
implausible internal values. Also python -m pytest tests/.python scripts/generate_index.py --with-jsonld.python wordpress/generate_neo_brutalist.py <slug>.Adds rider intel (challenges/terrain notes/tips/quotes from race recap
transcripts) and curated thumbnails to a profile's youtube_data block,
rendered as "RIDERS REPORT" callouts.
scripts/youtube_research.py --slug <slug> — populates videos[].
build_search_query() is discipline-aware, reads discipline from the race
JSON. [UNVERIFIED — session memory, Jul 2026: exact term mapping]scripts/youtube_enrich.py --slug <slug> (or --auto N) — curates real
race content (rejects indoor-trainer platforms, slideshows, promo reels,
sub-3min/over-2hr videos), sets curated/display_order.scripts/youtube_extract_intel.py --slug <slug> (or --auto N) — extracts
structured rider_intel from curated-video transcripts.scripts/youtube_thumbnail.py — fetches/scores thumbnails
(maxresdefault.jpg → hqdefault.jpg fallback), caches in
data/thumbnail-cache/ (30-day TTL, gitignored). [UNVERIFIED — session
memory, Jul 2026: exact scoring formula]scripts/youtube_validate.py — schema/format check before shipping.youtube_data across race-data/*.json for current counts
before quoting a percentage].scripts/scrape_utils.py (shared fetch/cache/extract) +
scripts/scrape_official_sites.py (CLI driver) + scripts/fact_check_profiles.py
(compares scraped facts vs profile, proposes fixes). Built for road-race
expansion batches; applies equally here.
Fetcher first, StealthyFetcher (Cloudflare bypass) on
failure. Use str(response.html_content), not response.text.data/scrape-cache/ (7-day TTL, gitignored, SHA-256 of URL). Extracts
land in data/scrape-extracts/{slug}.json (committed).scrape_official_sites.py --delay defaults 3.0s between sites —
don't lower against live race-org sites.road-race-automation git log for current
state before citing batch counts].After any bulk data edit (batch enrich, batch scrape-fix, mass score recompute), before deploy:
.claude/skills/scoring-and-veracity/SKILL.md
(scripts/verify_race_rankings.py, cross-checked against
docs/GRAVEL_GOD_SCORING_SYSTEM.md)..claude/skills/deploy-safely/SKILL.md
(scripts/preflight_quality.py, scripts/preflight.py --deploy).Skipping either on a bulk edit is how a wrong distance/elevation figure or a score/explanation mismatch (section 2) reaches production.
run_pipeline.py, pipeline/, gates/) — that's
the ENDURE athlete intake→plan engine living in this same repo, unrelated to
race-data profiles..claude/skills/deploy-safely/SKILL.md.docs/GRAVEL_GOD_SCORING_SYSTEM.md and
.claude/skills/scoring-and-veracity/SKILL.md.email-sequences skill.pytest tests/
and validate_race_data.py, no need for the full pipeline.