- Mode 1: Fix one existing issue, test, commit, report - Mode 2: Discover new issues with minimal documentation - Emphasize stopping after each cycle - Remove detailed investigation requirements - Simplify issue documentation format
13 KiB
How-To: Test Sync Against Production Data
Quick Start Prompt: Check work/active-issues/ for existing issues. If issues exist, pick the most important, fix it, test with cargo test, run clippy and fmt, commit, and report back with a brief 1-2 sentence summary of each issue you identified. If no issues exist, run a 30-second production sync test, analyze logs, create individual issue files in work/active-issues/ (one per issue with minimal description), then report summary listing each issue in 1-2 sentences.
Problem: Debug and improve sync behavior using real-world data from production relays
Difficulty: Intermediate
Time: 30 minutes per iteration
Two-Mode Workflow
This guide operates in two modes:
Mode 1: Fix Existing Issues
When: There are files in work/active-issues/ (excluding README.md)
- Check for active issues:
ls work/active-issues/ - Pick the most important issue to fix
- Implement the fix
- Run
cargo testto verify tests pass - Run
cargo clippyto check for warnings - Run
cargo fmtto format code - Commit changes with descriptive message
- Report back - DO NOT do another issue or run more tests
Mode 2: Discover New Issues
When: No active issues in work/active-issues/
- Run 30-second production sync test (logs saved to
tmp/run-{timestamp}/) - Analyze logs for errors, warnings, unexpected patterns
- Document each issue as a separate markdown file in
work/active-issues/ - Keep issue files minimal - just enough to identify the issue
- Report brief summary listing each issue in 1-2 sentences
- DO NOT create separate detailed analysis files
- DO NOT do thorough investigation or root cause analysis
Overview
This guide helps you run ngit-grasp's sync system against production relays to discover unexpected errors, inefficiencies, and edge cases that don't appear in controlled tests.
Why production testing matters:
- Real data has inconsistencies, malformed events, and edge cases
- Production relays may behave differently (rate limiting, timeouts, partial NIP-77 support)
- Volume and patterns reveal performance bottlenecks
- Sync discovery leads to cascading subscriptions we can't predict in tests
Prerequisites
- ngit-grasp compiles successfully (
cargo build) - Familiarity with GRASP-02 Proactive Sync
- Understanding of log levels and tracing
Test Setup
1. Choose a Test Identity
Pick a domain with manageable sync volume. Smaller domains mean fewer repos to sync, making logs tractable.
Recommended starting point:
--domain ngit.danconwaydev.com
This domain has few repo announcements listing it, so sync stays manageable.
2. Choose a Bootstrap Relay
The bootstrap relay provides the initial set of announcements to discover repos:
--sync-bootstrap-relay-url wss://git.shakespeare.diy
3. Run with Time Limit
Start with short runs (30 seconds) to capture manageable log volumes. Each run creates its own subdirectory in tmp/ to keep data and logs isolated:
# Create run directory with timestamp
RUN_DIR="tmp/run-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$RUN_DIR"
# Run for 30 seconds with sanitized output
timeout 30s cargo run -- \
--sync-bootstrap-relay-url wss://git.shakespeare.diy \
--domain ngit.danconwaydev.com \
--git-data-path "$RUN_DIR/git-data" \
--relay-data-path "$RUN_DIR/relay-data" \
2>&1 | ./scripts/sanitize-logs.sh | tee "$RUN_DIR/sync.log"
Note: The timeout command returns exit code 124, which is expected.
Directory structure after run:
tmp/
└── run-20260109-143022/
├── git-data/ # Git repository data
├── relay-data/ # Relay database
└── sync.log # Sanitized log output
Log Sanitization
Raw logs include full events and hundreds of event IDs per line, making them unwieldy for analysis. The sanitizer truncates long lines:
./scripts/sanitize-logs.sh < raw.log > sanitized.log
# Or pipe directly
cargo run -- [args] 2>&1 | ./scripts/sanitize-logs.sh
Options:
--head-chars N- First N characters to show (default: 200)--tail-chars N- Last N characters to show (default: 100)
Example output:
2024-01-09T10:00:00Z DEBUG sync: Processing events ids=[abc123, def456, ghi789, jkl012...<1847 chars>...xyz999, end123]
What to Look For
Phase 1: Connection & Bootstrap (0-5 seconds)
Expected behavior:
- Connection to bootstrap relay succeeds
- Layer 1 (announcement) subscription starts
- First batch of 30617/30618 events received
Red flags:
- Connection timeout or failure
- NIP-77 negentropy errors (should fall back gracefully)
- Immediate rate limiting
Phase 2: Discovery Cascade (5-15 seconds)
Expected behavior:
- Self-subscriber batches fire as announcements are processed
- New relays discovered from announcement
relaystags - Layer 2 (repo tags) subscriptions created
Red flags:
- Excessive relay discovery (>10 relays rapidly)
- Filter consolidation warnings (>70 filters)
- Missing self-subscriber batch logs
Phase 3: Steady State (15+ seconds)
Expected behavior:
- Historic sync batches completing (EOSE received)
- Periodic health checks running
- Events being saved to database
Red flags:
- Pending batches never confirming
- Repeated connection/disconnect cycles
- Memory growth (check with
topin another terminal)
Debugging Checklist
When analyzing logs, look for these patterns:
Errors to Investigate
| Pattern | Possible Cause | Action |
|---|---|---|
error (any) |
Unexpected failure | Investigate immediately |
connection failed |
Network/relay issue | Check relay URL, try different relay |
rate limit |
Too many requests | Check consolidation, increase backoff |
negentropy + error |
NIP-77 incompatibility | Should fall back - verify it does |
timeout |
Slow relay or large sync | Increase timeouts or reduce scope |
Warnings to Monitor
| Pattern | Meaning | Action |
|---|---|---|
consolidating filters |
Filter count high | Expected, but frequent = problem |
backing off |
Health tracker retry | Normal, but watch for excessive |
batch failed |
Historic sync incomplete | Check which batches, why |
Debug Patterns to Verify
| Pattern | What it shows |
|---|---|
fresh_start |
Full sync initiated |
quick_reconnect |
Incremental sync (<15min gap) |
historic sync complete |
Sync finished successfully |
sync_live |
Live subscriptions active |
PendingBatch |
Items awaiting EOSE confirmation |
Mode 1: Fix Existing Issues (Detailed)
When work/active-issues/ contains issue files:
Step 1: Check for Active Issues
ls work/active-issues/
If any .md files exist (excluding README.md), you're in Mode 1.
Step 2: Pick Most Important Issue
Review issue files and select based on:
- Severity (errors > warnings > log quality)
- Impact (functionality > performance > UX)
- Complexity (quick fixes first to clear backlog)
Step 3: Implement the Fix
Make the necessary code changes based on the issue description.
Step 4: Test, Lint, Format
# Run tests
cargo test
# Check for warnings
cargo clippy
# Format code
cargo fmt
Step 5: Commit
git add .
git commit -m "fix: [brief description of what was fixed]"
Step 6: Report Back
STOP HERE. Report what was fixed. Do NOT:
- Fix another issue
- Run production sync test
- Do additional investigation
The workflow will cycle back through Mode 1 if more issues remain.
Mode 2: Discover New Issues (Detailed)
When work/active-issues/ is empty (or only contains README.md):
Step 1: Run Production Sync Test
# Create run directory with timestamp
RUN_DIR="tmp/run-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$RUN_DIR"
# Run 30-second test
timeout 30s cargo run -- \
--sync-bootstrap-relay-url wss://git.shakespeare.diy \
--domain ngit.danconwaydev.com \
--git-data-path "$RUN_DIR/git-data" \
--relay-data-path "$RUN_DIR/relay-data" \
2>&1 | ./scripts/sanitize-logs.sh | tee "$RUN_DIR/sync.log"
Each run is isolated in its own timestamped directory under tmp/, keeping data and logs organized.
Step 2: Analyze Logs
Scan for errors and unexpected patterns:
# Find the most recent run
LATEST_RUN=$(ls -1t tmp/run-*/sync.log | head -n1)
# Analyze for issues
grep -i error "$LATEST_RUN"
grep -i warn "$LATEST_RUN"
grep -i panic "$LATEST_RUN"
Step 3: Document Issues
Create one markdown file per issue in work/active-issues/:
# Example: Minimal issue documentation
cat > work/active-issues/bootstrap-disconnect.md <<'EOF'
# Bootstrap relay disconnects when empty
Bootstrap relay wss://git.shakespeare.diy disconnects after sync finds 0 events. Should persist since user-specified.
Log: "Disconnecting empty relay relay=wss://git.shakespeare.diy"
File: src/sync/mod.rs (check_disconnects function)
EOF
Keep each file brief:
- Descriptive title (one line)
- What happens (1-2 sentences max)
- Relevant log excerpt (one line)
- File/function location if obvious (one line)
- NO separate detailed analysis files
- NO root cause analysis
- NO proposed solutions (unless immediately obvious)
Step 4: Report Summary
Provide a brief closing message with 1-2 sentence summary of each issue identified:
- State what the issue is
- Where it occurs (file/component)
- Keep it concise
STOP HERE. Do NOT:
- Fix the issues immediately
- Create separate detailed analysis markdown files
- Do thorough investigations
- Write lengthy explanations
The workflow will cycle back through Mode 1 to fix issues one at a time.
Logging Improvements
If the logs aren't helpful enough, improve them. Common needs:
Add Context to Existing Logs
// Before
tracing::debug!("Processing events");
// After
tracing::debug!(
relay = %relay_url,
event_count = events.len(),
"Processing events"
);
Add New Log Points
Key places that may need more logging:
src/sync/mod.rs- SyncManager state transitionssrc/sync/relay_connection.rs- Connection lifecyclesrc/sync/self_subscriber.rs- Batch processing
Reduce Noise
If a log line appears too frequently:
// Change from debug! to trace!
tracing::trace!("Per-event detail that's too noisy");
Managing Active Issues
Issues are tracked in work/active-issues/ as individual markdown files.
Check for active issues:
ls work/active-issues/
After fixing an issue:
# Delete the resolved issue file
rm work/active-issues/issue-name.md
# Or archive if important for future reference
mv work/active-issues/issue-name.md docs/archive/2026-01-09-issue-name.md
Issue file format (minimal):
# Brief title
What happens (1-2 sentences).
Log evidence: "relevant log line"
File: src/path/to/file.rs (function_name if known)
Keep documentation minimal - just enough to identify and locate the issue.
Workflow Summary
Check work/active-issues/
│
├─ Has issues? ──► Mode 1: Pick one issue
│ │
│ ├─ Fix code
│ ├─ cargo test
│ ├─ cargo clippy
│ ├─ cargo fmt
│ ├─ git commit
│ └─ Report & STOP
│
└─ No issues? ──► Mode 2: Run production sync
│
├─ timeout 30s cargo run ...
├─ Analyze logs
├─ Document issues (minimal)
└─ Report summary & STOP
Key Rules:
- Only do ONE thing per cycle (fix one issue OR discover issues)
- Always stop after reporting
- Keep issue documentation minimal
- No root cause analysis during discovery
Quick Reference
Minimal Test Command
# Create run directory
RUN_DIR="tmp/run-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$RUN_DIR"
# Run test
timeout 30s cargo run -- \
--sync-bootstrap-relay-url wss://git.shakespeare.diy \
--domain ngit.danconwaydev.com \
--git-data-path "$RUN_DIR/git-data" \
--relay-data-path "$RUN_DIR/relay-data" \
2>&1 | ./scripts/sanitize-logs.sh | tee "$RUN_DIR/sync.log"
With Metrics Endpoint
# Create run directory
RUN_DIR="tmp/run-$(date +%Y%m%d-%H%M%S)"
mkdir -p "$RUN_DIR"
# Run with metrics
timeout 30s cargo run -- \
--sync-bootstrap-relay-url wss://git.shakespeare.diy \
--domain ngit.danconwaydev.com \
--git-data-path "$RUN_DIR/git-data" \
--relay-data-path "$RUN_DIR/relay-data" \
--metrics-address 127.0.0.1:9090 \
2>&1 | ./scripts/sanitize-logs.sh | tee "$RUN_DIR/sync.log"
Then in another terminal: curl http://127.0.0.1:9090/metrics
Cleanup Old Runs
# Remove runs older than 7 days
find tmp/run-* -type d -mtime +7 -exec rm -rf {} +
# Remove all test runs
rm -rf tmp/run-*
Different Log Level
The default is DEBUG. For more detail:
RUST_LOG=trace cargo run -- [args]
For less noise:
RUST_LOG=info cargo run -- [args]
Part of the ngit-grasp documentation using the Diátaxis framework.