| name | golden-dataset-management |
| description | Backup, restore, and validate golden datasets for AI/ML systems - ensuring test data integrity and preventing catastrophic data loss |
| version | 2.0.0 |
| author | YG Starter AI Agent Hub |
| tags | ["golden-dataset","backup","data-protection","testing","regression",2025] |
Golden Dataset Management
Protect and maintain high-quality test datasets for AI/ML systems
Overview
A golden dataset is a curated collection of high-quality examples used for:
- Regression testing: Ensure new code doesn't break existing functionality
- Retrieval evaluation: Measure search quality (precision, recall, MRR)
- Model benchmarking: Compare different models/approaches
- Reproducibility: Consistent results across environments
When to use this skill:
- Building test datasets for RAG systems
- Implementing backup/restore for critical data
- Validating data integrity (URL contracts, embeddings)
- Migrating data between environments
Example Production Dataset
Typical Stats:
- 100-500 documents (curated technical content)
- 400-2000 chunks (embedded text segments)
- 200-1000 test queries (with expected results)
- 85-95% pass rate (retrieval quality metric)
Purpose:
- Test hybrid search (vector + BM25 + RRF)
- Validate metadata boosting strategies
- Detect regressions in retrieval quality
- Benchmark new embedding models
- A/B test different chunking strategies
Core Concepts
1. Data Integrity Contracts
The URL Contract:
Golden dataset analyses MUST store real canonical URLs, not placeholders.
analysis.url = "https://project.dev/placeholder/123"
analysis.url = "https://docs.python.org/3/library/asyncio.html"
Why this matters:
- Enables re-fetching content if embeddings need regeneration
- Allows validation that source content hasn't changed
- Provides audit trail for data provenance
Verification:
def verify_url_contract(analyses: list[Analysis]) -> list[str]:
"""Find analyses with placeholder URLs."""
invalid = []
for analysis in analyses:
if "project.dev" in analysis.url or "placeholder" in analysis.url:
invalid.append(analysis.id)
return invalid
2. Backup Strategies
Strategy 1: JSON Backup (Recommended)
Pros:
- Version controlled (commit to git)
- Human-readable (easy to inspect)
- Portable (works across DB versions)
- Incremental diffs (see what changed)
Cons:
- Must regenerate embeddings on restore
- Larger file size than SQL dump
Recommended: Use JSON backup for version control.
Strategy 2: SQL Dump
Pros:
- Fast restore (includes embeddings)
- Exact replica (binary-identical)
- Native PostgreSQL format
Cons:
- Not version controlled (binary format)
- DB version dependent
- No easy inspection
Use case: Local snapshots, not version control.
3. Backup Format
{
"version": "1.0",
"created_at": "2025-12-19T10:30:00Z",
"metadata": {
"total_analyses": 98,
"total_chunks": 415,
"total_artifacts": 98
},
"analyses": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://docs.python.org/3/library/asyncio.html",
"content_type": "documentation",
"status": "completed",
"created_at": "2025-11-15T08:20:00Z",
"findings": [
{
"agent": "security_agent"
Key Design Decisions:
- Embeddings excluded (regenerate on restore with current model)
- Nested structure (analyses → chunks → artifacts)
- Metadata for validation
- ISO timestamps for reproducibility
Backup Implementation
Script Structure
import asyncio
import json
from datetime import datetime, UTC
from pathlib import Path
from sqlalchemy import select
from app.db.session import get_session
from app.db.models import Analysis, Chunk, Artifact
BACKUP_DIR = Path("backend/data")
BACKUP_FILE = BACKUP_DIR / "golden_dataset_backup.json"
METADATA_FILE = BACKUP_DIR / "golden_dataset_metadata.json"
async def backup_golden_dataset():
"""Backup golden dataset to JSON."""
async with get_session() as session:
query = (
select(Analysis)
.where(Analysis.status == "completed")
.order_by(Analysis.created_at)
)
result = await session.execute(query)
analyses = result.scalars().all()
backup_data = {
"version": "1.0",
"created_at": datetime.now(UTC).isoformat(),
"metadata": {
"total_analyses": len(analyses),
"total_chunks": sum(len(a.chunks) for a in analyses),
"total_artifacts": len([a for a analyses a.artifact])
},
: [
serialize_analysis(a) a analyses
]
}
BACKUP_DIR.mkdir(exist_ok=)
(BACKUP_FILE, ) f:
json.dump(backup_data, f, indent=, default=)
(METADATA_FILE, ) f:
json.dump(backup_data[], f, indent=)
()
()
()
() -> :
{
: (analysis.),
: analysis.url,
: analysis.content_type,
: analysis.status,
: analysis.created_at.isoformat(),
: [serialize_finding(f) f analysis.findings],
: [serialize_chunk(c) c analysis.chunks],
: serialize_artifact(analysis.artifact) analysis.artifact
}
() -> :
{
: (chunk.),
: chunk.content,
: chunk.section_title,
: chunk.section_path,
: chunk.content_type,
: chunk.chunk_index
}
Detailed Implementation: See templates/backup-script.py
Restore Implementation
Process Overview
- Load JSON backup
- Validate structure (version, required fields)
- Create analyses (without embeddings yet)
- Create chunks (without embeddings yet)
- Generate embeddings (using current embedding model)
- Create artifacts
- Verify integrity (counts, URL contract)
Key Challenge: Regenerating Embeddings
async def restore_golden_dataset(replace: bool = False):
"""Restore golden dataset from JSON backup."""
with open(BACKUP_FILE) as f:
backup_data = json.load(f)
async with get_session() as session:
if replace:
await session.execute(delete(Chunk))
await session.execute(delete(Artifact))
await session.execute(delete(Analysis))
await session.commit()
from app.shared.services.embeddings import embed_text
for analysis_data in backup_data["analyses"]:
analysis = Analysis(
id=UUID(analysis_data["id"]),
url=analysis_data["url"],
)
session.add(analysis)
for chunk_data in analysis_data["chunks"]:
embedding = await embed_text(chunk_data["content"])
chunk = Chunk(
id=UUID(chunk_data["id"]),
analysis_id=analysis.,
content=chunk_data[],
embedding=embedding,
)
session.add(chunk)
session.commit()
()
Why regenerate embeddings?
- Embedding models improve over time
- Ensures consistency with current model
- Smaller backup files (exclude large vectors)
Detailed Implementation: See references/backup-restore.md
Validation
Validation Checklist
async def verify_golden_dataset() -> dict:
"""Verify golden dataset integrity."""
errors = []
warnings = []
async with get_session() as session:
analysis_count = await session.scalar(select(func.count(Analysis.id)))
chunk_count = await session.scalar(select(func.count(Chunk.id)))
artifact_count = await session.scalar(select(func.count(Artifact.id)))
expected = load_metadata()
if analysis_count != expected["total_analyses"]:
errors.append(f"Analysis count mismatch: {analysis_count} vs {expected['total_analyses']}")
query = select(Analysis).where(
Analysis.url.like("%project.dev%") |
Analysis.url.like("%placeholder%")
)
result = await session.execute(query)
invalid_urls = result.scalars().all()
if invalid_urls:
errors.append(f"Found {len(invalid_urls)} analyses with placeholder URLs")
query = select(Chunk).where(Chunk.embedding.is_(None))
result = await session.execute(query)
missing_embeddings = result.scalars().all()
if missing_embeddings:
errors.append(f"Found {len(missing_embeddings)} chunks without embeddings")
query = select(Chunk).outerjoin(Analysis).where(Analysis..is_())
result = session.execute(query)
orphaned = result.scalars().()
orphaned:
warnings.append()
{
: (errors) == ,
: errors,
: warnings,
: {
: analysis_count,
: chunk_count,
: artifact_count
}
}
Detailed Validation: See references/validation-contracts.md
CLI Usage
cd backend
uv run python scripts/backup_golden_dataset.py backup
uv run python scripts/backup_golden_dataset.py verify
uv run python scripts/backup_golden_dataset.py restore --replace
uv run python scripts/backup_golden_dataset.py restore
CI/CD Integration
Automated Backups
name: Backup Golden Dataset
on:
schedule:
- cron: '0 2 * * 0'
workflow_dispatch:
jobs:
backup:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: |
cd backend
uv sync
- name: Run backup
env:
DATABASE_URL: ${{ secrets.PROD_DATABASE_URL }}
run: |
cd backend
uv run python scripts/backup_golden_dataset.py backup
- name: Commit backup
run: |
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git add backend/data/golden_dataset_backup.json
git add backend/data/golden_dataset_metadata.json
git commit -m "chore: automated golden dataset backup"
git push
Best Practices
1. Version Control Backups
git add backend/data/golden_dataset_backup.json
git commit -m "chore: golden dataset backup (98 analyses, 415 chunks)"
2. Validate Before Deployment
uv run python scripts/backup_golden_dataset.py verify
3. Test Restore in Staging
export DATABASE_URL=$STAGING_DATABASE_URL
uv run python scripts/backup_golden_dataset.py restore --replace
uv run pytest tests/integration/test_retrieval_quality.py
4. Document Changes
{
"total_analyses": 98,
"total_chunks": 415,
"last_updated": "2025-12-19T10:30:00Z",
"changes": [
{
"date": "2025-12-19",
"action": "added",
"count": 5,
"description": "Added 5 new LangGraph tutorial analyses"
},
{
"date": "2025-12-10",
"action": "removed",
"count": 2,
"description": "Removed 2 outdated React 17 analyses"
}
]
}
Disaster Recovery
Scenario 1: Accidental Deletion
uv run python scripts/backup_golden_dataset.py restore --replace
uv run python scripts/backup_golden_dataset.py verify
uv run pytest tests/integration/test_retrieval_quality.py
Scenario 2: Database Migration Gone Wrong
alembic downgrade -1
uv run python scripts/backup_golden_dataset.py restore --replace
alembic upgrade head
Scenario 3: New Environment Setup
git clone https://github.com/your-org/project
cd project/backend
docker compose up -d postgres
alembic upgrade head
uv run python scripts/backup_golden_dataset.py restore
uv run pytest tests/integration/test_retrieval_quality.py
References
Example Implementation Files
backend/scripts/backup_golden_dataset.py - Main backup script
backend/data/golden_dataset_backup.json - JSON backup (version controlled)
backend/data/golden_dataset_metadata.json - Quick stats
Related Skills
pgvector-search - Retrieval evaluation using golden dataset
ai-native-development - Embedding generation for restore
devops-deployment - CI/CD backup automation
2025 Best Practices Update
Incremental Backups
from pathlib import Path
import json
from datetime import datetime, UTC
class IncrementalBackup:
"""Incremental backup with change tracking."""
def __init__(self, backup_dir: Path):
self.backup_dir = backup_dir
self.backup_dir.mkdir(exist_ok=True)
async def create_incremental_backup(self) -> Path:
"""Create incremental backup (only changed documents)."""
hash_file = self.backup_dir / "document_hashes.json"
previous_hashes = {}
if hash_file.exists():
with open(hash_file) as f:
previous_hashes = json.load(f)
async with get_session() as session:
query = select(Analysis).where(Analysis.status == "completed")
result = await session.execute(query)
analyses = result.scalars().all()
changed = []
current_hashes = {}
for analysis in analyses:
content = json.dumps(serialize_analysis(analysis), sort_keys=True)
current_hash = hashlib.sha256(content.encode()).hexdigest()
current_hashes[str(analysis.)] = current_hash
previous_hashes.get((analysis.)) != current_hash:
changed.append(analysis)
timestamp = datetime.now(UTC).strftime()
backup_file = .backup_dir /
(backup_file, ) f:
json.dump({
: ,
: ,
: datetime.now(UTC).isoformat(),
: (analyses),
: (changed),
: [serialize_analysis(a) a changed],
}, f, indent=)
(hash_file, ) f:
json.dump(current_hashes, f, indent=)
()
backup_file
Compression for Large Datasets
import gzip
import json
def save_compressed_backup(data: dict, path: Path):
"""Save compressed JSON backup."""
with gzip.open(f"{path}.gz", "wt", encoding="utf-8") as f:
json.dump(data, f, indent=2, default=str)
def load_compressed_backup(path: Path) -> dict:
"""Load compressed JSON backup."""
with gzip.open(f"{path}.gz", "rt", encoding="utf-8") as f:
return json.load(f)
Version: 2.0.0 (January 2025)
Status: Production-ready patterns for AI/ML dataset management