upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/docs/explanation/comparison.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/explanation/comparison.md')
-rw-r--r--docs/explanation/comparison.md495
1 files changed, 309 insertions, 186 deletions
diff --git a/docs/explanation/comparison.md b/docs/explanation/comparison.md
index be16f9e..72e49a7 100644
--- a/docs/explanation/comparison.md
+++ b/docs/explanation/comparison.md
@@ -1,256 +1,379 @@
1# ngit-grasp vs ngit-relay Comparison 1# ngit-grasp vs ngit-relay Comparison
2 2
3## High-Level Comparison 3This document compares ngit-grasp (this project) with ngit-relay (the reference implementation) based on their actual implementations.
4
5## High-Level Overview
4 6
5| Aspect | ngit-relay (Reference) | ngit-grasp (This Project) | 7| Aspect | ngit-relay (Reference) | ngit-grasp (This Project) |
6|--------|------------------------|---------------------------| 8|--------|------------------------|---------------------------|
7| **Language** | Go | Rust | 9| **Language** | Go | Rust |
8| **Architecture** | Multi-process (nginx, git-http-backend, hooks, relay) | Single integrated process | 10| **Architecture** | Multi-process (nginx + fcgiwrap + khatru + sync daemon) | Single integrated process |
9| **Authorization** | Git pre-receive hook | Inline HTTP handler | 11| **Git Protocol** | git-http-backend (C via fcgiwrap) | HTTP layer in Rust + git subprocess |
10| **Packaging** | Docker + supervisord | Single binary or Docker | 12| **Authorization** | Pre-receive Git hook | Inline HTTP handler validation |
11| **Configuration** | Multiple config files | Environment variables | 13| **Nostr Relay** | Khatru (Go library) | nostr-relay-builder (Rust library) |
12| **Deployment** | Docker Compose | Binary or Docker | 14| **Event Store** | Badger (Go KV database) | LMDB or NostrDB (Rust) |
13| **Testing** | Go tests + shell scripts | Rust unit + integration tests | 15| **Proactive Sync** | Git-only (polls DB + fetches from git servers) | Nostr event sync + git sync (event-driven) |
16| **Process Management** | supervisord (4 processes) | Single tokio runtime |
17| **Packaging** | Docker with supervisord | Single static binary or Docker |
18| **Configuration** | Environment variables | Environment variables + CLI flags |
19| **Total Code** | ~1,866 lines of Go | ~25,000 lines of Rust |
14 20
15## Component Breakdown 21## Architecture Comparison
16 22
17### ngit-relay (Go) 23### ngit-relay (Multi-Process)
18 24
19``` 25```
20┌─────────────────────────────────────────────────┐ 26┌──────────────── Docker Container ────────────────┐
21│ Docker Container │ 27│ │
22├─────────────────────────────────────────────────┤ 28│ ┌─────────────────────────────────────────────┐ │
23│ │ 29│ │ supervisord │ │
24│ ┌──────────┐ ┌─────────────────────┐ │ 30│ │ - fcgiwrap (git-http-backend wrapper) │ │
25│ │ nginx │────────▶│ git-http-backend │ │ 31│ │ - nginx (HTTP + reverse proxy) │ │
26│ │ :80 │ │ (C binary) │ │ 32│ │ - ngit-relay-khatru (Nostr relay) │ │
27│ └──────────┘ └──────────┬──────────┘ │ 33│ │ - ngit-relay-proactive-sync (sync daemon) │ │
28│ │ │ │ 34│ └─────────────────────────────────────────────┘ │
29│ │ ▼ │ 35│ │
30│ │ ┌─────────────────┐ │ 36│ ┌──────────┐ ┌────────────────────┐ │
31│ │ │ Git Repo │ │ 37│ │ nginx │────────▶│ git-http-backend │ │
32│ │ │ + Hooks │ │ 38│ │ :80 │ │ (C binary via CGI) │ │
33│ │ └────────┬────────┘ │ 39│ └──────┬───┘ └──────────┬─────────┘ │
34│ │ │ │ 40│ │ │ │
35│ │ ▼ │ 41│ │ ▼ │
36│ │ ┌─────────────────┐ │ 42│ │ ┌──────────────────┐ │
37│ │ │ pre-receive │ │ 43│ │ │ Git Repos │ │
38│ │ │ (Go binary) │ │ 44│ │ │ + pre-receive │ │
39│ │ └────────┬────────┘ │ 45│ │ │ hook (Go) │ │
40│ │ │ │ 46│ │ └────────┬─────────┘ │
41│ │ │ WebSocket │ 47│ │ │ WebSocket │
42│ │ ▼ │ 48│ │ │ query │
43│ │ ┌─────────────────┐ │ 49│ │ ▼ │
44│ └─────────────────▶│ Khatru Relay │ │ 50│ │ ┌──────────────────┐ │
45│ │ (Go) │ │ 51│ └──────────────▶│ Khatru Relay │ │
46│ └─────────────────┘ │ 52│ │ :3334 │ │
47│ │ 53│ │ (Badger DB) │ │
48│ ┌──────────────────────────────────────────┐ │ 54│ └──────────────────┘ │
49│ │ supervisord │ │ 55│ │
50│ │ - nginx │ │ 56│ Separate sync daemon polls relay DB │
51│ │ - khatru │ │ 57│ and fetches from remote git servers │
52│ │ - proactive-sync │ │ 58│ │
53│ └──────────────────────────────────────────┘ │ 59└───────────────────────────────────────────────────┘
54│ │
55└─────────────────────────────────────────────────┘
56``` 60```
57 61
58### ngit-grasp (Rust) 62### ngit-grasp (Single Process)
59 63
60``` 64```
61┌─────────────────────────────────────────────────┐ 65┌────────────── ngit-grasp (Single Binary) ─────────────┐
62│ ngit-grasp (Single Binary) │ 66│ │
63├─────────────────────────────────────────────────┤ 67│ ┌──────────────────────────────────────────────────┐ │
64│ │ 68│ │ hyper HTTP Server (:8080) │ │
65│ ┌──────────────────────────────────────────┐ │ 69│ │ - WebSocket upgrade for Nostr relay │ │
66│ │ actix-web HTTP Server │ │ 70│ │ - Git Smart HTTP handlers │ │
67│ │ :8080 │ │ 71│ │ - Landing page + metrics endpoint │ │
68│ └───────┬──────────────────────┬────────────┘ │ 72│ └───────┬──────────────────────┬───────────────────┘ │
69│ │ │ │ 73│ │ │ │
70│ ▼ ▼ │ 74│ ▼ ▼ │
71│ ┌──────────────┐ ┌──────────────────┐ │ 75│ ┌──────────────┐ ┌────────────────────┐ │
72│ │ Git Handlers │ │ Nostr Relay │ │ 76│ │ Git Handlers │ │ Nostr Relay │ │
73│ │ │ │ (relay-builder) │ │ 77│ │ (HTTP layer) │ │ (nostr-relay- │ │
74│ │ - upload-pk │ │ │ │ 78│ │ │ │ builder library) │ │
75│ │ - receive-pk │◀─────│ - Policies │ │ 79│ │ - info/refs │ │ - NIP-34 Policy │ │
76│ │ + inline │ query│ - Event store │ │ 80│ │ - upload-pk │◀─────┤ (inline query) │ │
77│ │ validation │ │ - WebSocket │ │ 81│ │ - receive-pk │ auth │ - LMDB/NostrDB │ │
78│ └──────┬───────┘ └──────────────────┘ │ 82│ │ + inline │ check│ - WebSocket │ │
79│ │ │ 83│ │ validation │ │ - NIP-11 endpoint │ │
80│ ▼ │ 84│ └──────┬───────┘ └──────────┬─────────┘ │
81│ ┌──────────────┐ │ 85│ │ │ │
82│ │ Git Repos │ │ 86│ ▼ ▼ │
83│ │ (spawned │ │ 87│ ┌──────────────┐ ┌────────────────────┐ │
84│ │ git cmds) │ │ 88│ │ git binary │ │ Purgatory │ │
85│ └──────────────┘ │ 89│ │ upload-pack │ │ (in-memory queue) │ │
86│ │ 90│ │ receive-pk │ │ + sync loop │ │
87│ ┌──────────────────────────────────────────┐ │ 91│ └──────────────┘ └────────────────────┘ │
88│ │ Shared State (Arc<AppState>) │ │ 92│ │
89│ │ - RepositoryManager │ │ 93│ ┌──────────────────────────────────────────────────┐ │
90│ │ - NostrClient │ │ 94│ │ SyncManager (tokio background task) │ │
91│ │ - StateCache │ │ 95│ │ - Multi-relay Nostr event sync (GRASP-02) │ │
92│ └──────────────────────────────────────────┘ │ 96│ │ - Negentropy + REQ/EOSE support │ │
93│ │ 97│ │ - Health tracking & exponential backoff │ │
94└─────────────────────────────────────────────────┘ 98│ │ - Git fetch from remote servers (via purgatory) │ │
99│ └──────────────────────────────────────────────────┘ │
100│ │
101│ ┌──────────────────────────────────────────────────┐ │
102│ │ Shared State (Arc<T>) │ │
103│ │ - Database (LMDB/NostrDB/Memory) │ │
104│ │ - Purgatory (DashMap - concurrent queue) │ │
105│ │ - Metrics (Prometheus) │ │
106│ └──────────────────────────────────────────────────┘ │
107│ │
108└────────────────────────────────────────────────────────┘
95``` 109```
96 110
97## Detailed Feature Comparison 111## Feature Comparison
112
113### Key Architectural Difference: Nostr Event Sync
114
115**The biggest difference between the two implementations is how they handle Nostr events:**
116
117| Aspect | ngit-relay | ngit-grasp |
118|--------|-----------|-----------|
119| **Event Arrival** | Relies on clients to push events directly | Proactively syncs events from other relays |
120| **Discovery** | None - only stores what clients send | Discovers events from relay network |
121| **Coordination** | Events and git data handled separately | Purgatory coordinates events + git data |
122| **Completeness** | May miss events if clients don't push to this relay | Actively fetches missing events from network |
123| **Implementation** | No event sync code (~0 lines) | Full multi-relay sync system (~5,000 lines) |
124
125**Example scenario:**
126- User creates PR on relay A, pushes git data to server B
127- **ngit-relay**: Only knows about events/data pushed directly to it
128- **ngit-grasp**: Discovers PR event from relay A, fetches git data from server B
129
130This is why ngit-grasp has ~13x more code - the majority is implementing GRASP-02 proactive event sync.
98 131
99### Git Protocol Handling 132### Git Protocol Implementation
100 133
101| Feature | ngit-relay | ngit-grasp | 134| Feature | ngit-relay | ngit-grasp |
102|---------|-----------|-----------| 135|---------|-----------|-----------|
103| Implementation | git-http-backend (C) | git-http-backend (Rust crate) | 136| **HTTP Server** | nginx | hyper (Rust) |
104| Process model | nginx → C binary | actix-web → Rust handler | 137| **Git Backend** | git-http-backend (C) via fcgiwrap | HTTP protocol layer (Rust) + git binary |
105| Upload pack | Passthrough | Passthrough with validation | 138| **Process Model** | FastCGI spawns git-http-backend | HTTP handler spawns git subprocess |
106| Receive pack | Hook-based auth | Inline validation | 139| **Upload Pack** | C binary passthrough | Rust parses HTTP → spawns `git upload-pack` |
107| Error handling | Hook stderr | HTTP response | 140| **Receive Pack** | C binary → pre-receive hook | Rust validates → spawns `git receive-pack` |
108| CORS | nginx config | actix-cors middleware | 141| **Authorization** | Go hook queries relay via WebSocket | In-process function call before git spawn |
142| **Error Reporting** | Hook stderr → git client | HTTP response body (before git runs) |
143| **CORS** | nginx config | hyper middleware |
144| **Lines of Code** | ~0 (uses C binary) + hook ~135 | ~1,000+ (HTTP protocol layer) |
109 145
110### Nostr Relay 146### Authorization Logic
111 147
112| Feature | ngit-relay | ngit-grasp | 148| Feature | ngit-relay | ngit-grasp |
113|---------|-----------|-----------| 149|---------|-----------|-----------|
114| Implementation | Khatru (Go) | nostr-relay-builder (Rust) | 150| **Location** | pre-receive hook (separate Go binary) | Inline HTTP handler (Rust) |
115| Event store | Badger (Go) | LMDB or NDB (Rust) | 151| **Trigger** | Git invokes hook during push | HTTP handler before spawning git |
116| Policies | Go functions | Rust traits | 152| **State Query** | WebSocket to localhost:3334 | Direct database query (in-process) |
117| WebSocket | Khatru built-in | nostr-relay-builder | 153| **Latency** | +50-100ms (hook spawn + WS query) | +10-20ms (function call) |
118| NIP-11 | Manual JSON | Built-in support | 154| **Error Channel** | stderr → git client | HTTP 403 response |
155| **Ref Parsing** | Read from stdin (hook protocol) | Parse from HTTP request body |
156| **Maintainer Resolution** | Recursive Go function | Recursive Rust function (similar) |
157| **State Caching** | None (queries relay per push) | Purgatory tracks pending events |
119 158
120### Authorization Logic 159### Nostr Relay
160
161| Feature | ngit-relay | ngit-grasp |
162|---------|-----------|-----------|
163| **Implementation** | Khatru (Go library) | nostr-relay-builder (Rust library) |
164| **Database** | Badger (Go KV store) | LMDB or NostrDB (Rust) |
165| **Process** | Separate process on :3334 | Integrated (same binary) |
166| **Policies** | Go functions in `policies.go` | Rust traits (modular sub-policies) |
167| **Event Validation** | Single function with branches | 4 separate policy modules |
168| **WebSocket** | Khatru built-in | nostr-relay-builder + hyper |
169| **NIP-11** | Manual JSON in code | Built-in support from library |
170| **Connection** | Separate from HTTP | Shared hyper server |
171| **Lines of Code** | ~186 (policies.go) + Khatru library | ~3,000+ (policy modules) + nostr-relay-builder library |
172
173### Proactive Sync
121 174
122| Feature | ngit-relay | ngit-grasp | 175| Feature | ngit-relay | ngit-grasp |
123|---------|-----------|-----------| 176|---------|-----------|-----------|
124| Location | pre-receive hook | HTTP handler | 177| **Architecture** | Separate daemon (`ngit-relay-proactive-sync`) | Integrated SyncManager (tokio task) |
125| Language | Go | Rust | 178| **Nostr Event Sync** | ❌ None (relies on client pushes) | ✅ Multi-relay sync with negentropy/REQ |
126| State query | WebSocket to localhost:3334 | In-process function call | 179| **Git Data Sync** | ✅ Polls local DB + fetches from git servers | ✅ Event-driven via purgatory queue |
127| Error reporting | stderr → git client | HTTP response body | 180| **Sync Trigger** | Timer (every 15 minutes) | Immediate on event arrival + timer for retries |
128| Ref validation | Line-by-line stdin | Parsed from request body | 181| **Relay Discovery** | N/A (no event sync) | Dynamic from 30617 announcement events |
129| Maintainer resolution | Recursive Go function | Recursive Rust function | 182| **Protocol** | Git fetch only | Nostr WebSocket + git fetch |
130| State caching | Per-request | Shared cache with TTL | 183| **Concurrency** | Goroutines (per-repo iteration) | Tokio async tasks (per-relay connections) |
184| **Health Tracking** | Basic retry on git fetch failures | RelayHealthTracker with exponential backoff |
185| **Connection Management** | N/A (no Nostr connections) | Persistent connections with reconnect |
186| **Coordination** | Separate process | Purgatory + SyncManager coordination |
187| **Lines of Code** | ~112 (main.go) + ~305 (git sync) | ~5,000+ (Nostr sync + git sync + coordination) |
131 188
132### Repository Management 189### Repository Management
133 190
134| Feature | ngit-relay | ngit-grasp | 191| Feature | ngit-relay | ngit-grasp |
135|---------|-----------|-----------| 192|---------|-----------|-----------|
136| Creation | Event hook + shell commands | Event hook + tokio::process | 193| **Creation** | Event hook → shell commands | Event hook → tokio::process |
137| Configuration | git config via shell | git config via tokio::process | 194| **Trigger** | `EventReceiveHook()` in Go | `handle_announcement()` in Rust |
138| Hook installation | Symlinks | Not needed (inline auth) | 195| **Configuration** | `git config` via shell | `git config` via tokio::process |
139| Permissions | chown nginx:nginx | tokio::fs permissions | 196| **Hook Installation** | Symlinks to pre-receive/post-receive | Not needed (inline auth) |
140| Path structure | `<npub>/<id>.git` | `<npub>/<id>.git` (same) | 197| **Permissions** | `chown nginx:nginx` | tokio::fs permissions |
198| **Path Structure** | `<npub>/<id>.git` | `<npub>/<id>.git` (same) |
141 199
142### Deployment 200### Event Coordination (Purgatory)
143 201
144| Feature | ngit-relay | ngit-grasp | 202| Feature | ngit-relay | ngit-grasp |
145|---------|-----------|-----------| 203|---------|-----------|-----------|
146| Dependencies | nginx, git, Go runtime | git, Rust binary (no runtime) | 204| **Implementation** | None | Dedicated Purgatory system |
147| Process management | supervisord | Single process (tokio) | 205| **Purpose** | N/A | Solves "which arrives first?" problem |
148| Configuration | Multiple files + .env | .env only | 206| **Storage** | N/A | In-memory DashMap (thread-safe) |
149| Docker image size | ~500MB (Alpine + tools) | ~50MB (scratch + binary + git) | 207| **Expiry** | N/A | 30 minutes default TTL |
150| Startup time | ~2-5 seconds | ~0.5 seconds | 208| **State Events** | Accepted (git sync happens later via timer) | Queued until git data arrives |
151| Memory usage | ~100-200MB (multiple processes) | ~50-100MB (single process) | 209| **PR Events** | Accepted (references may be missing) | Queued with placeholder refs |
210| **Sync Queue** | Timer-based (polls all repos) | Event-driven (only syncs needed repos) |
211| **Cleanup** | N/A | Background task (60s interval) |
212| **Lines of Code** | 0 | ~2,000+ |
152 213
153### Development Experience 214**Impact**: ngit-relay accepts all events and relies on periodic sync to eventually fetch git data. ngit-grasp holds events in purgatory and triggers targeted syncs, providing faster convergence and better coordination between Nostr events and git data.
215
216### Deployment & Operations
154 217
155| Feature | ngit-relay | ngit-grasp | 218| Feature | ngit-relay | ngit-grasp |
156|---------|-----------|-----------| 219|---------|-----------|-----------|
157| Build time | Fast (Go) | Medium (Rust first build, then fast) | 220| **Dependencies** | nginx, git, fcgiwrap, supervisord, Go runtime | git, Rust binary (statically linked) |
158| Type safety | Go (good) | Rust (excellent) | 221| **Process Count** | 4 (supervisord + nginx + khatru + sync) | 1 (single tokio runtime) |
159| Testing | Go test + shell | Rust test (unit + integration) | 222| **Configuration** | `.env` file | `.env` + CLI flags (clap) |
160| Debugging | Multiple processes | Single process | 223| **Docker Image Size** | ~500MB (Alpine + tools + Go runtime) | ~100MB (Debian slim + git + binary) |
161| Hot reload | Manual | cargo-watch | 224| **Startup Time** | ~2-5 seconds (multiple processes) | ~0.5 seconds (single process) |
162| IDE support | Good (Go) | Excellent (rust-analyzer) | 225| **Memory (Idle)** | ~150-200MB (4 processes + Go GC) | ~50-100MB (single process, no GC) |
226| **Logs** | supervisord → stdout (4 streams) | tracing → stdout (unified) |
227| **Monitoring** | None built-in | Prometheus metrics endpoint |
228| **Binary Distribution** | Docker only | Native binary + Docker |
229
230### Development Experience
163 231
164## Performance Comparison (Estimated) 232| Feature | ngit-relay | ngit-grasp |
233|---------|-----------|-----------|
234| **Build Time** | Fast (~5s incremental, Go) | Slow first build (~5min), fast incremental |
235| **Type Safety** | Good (Go interfaces) | Excellent (Rust traits + ownership) |
236| **Testing** | Go tests + shell scripts | Rust unit + integration tests |
237| **Test Relay** | Manual Docker setup | `TestRelay` fixture (auto-start binary) |
238| **Debugging** | Multi-process (harder) | Single process (easier) |
239| **IDE Support** | Good (gopls) | Excellent (rust-analyzer) |
240| **Async Model** | Goroutines (simple) | Tokio (more complex) |
241| **Error Handling** | `error` interface + if checks | Result<T, E> + `?` operator |
242| **Dependencies** | Go modules | Cargo crates (larger ecosystem) |
243
244### Code Complexity
245
246| Component | ngit-relay | ngit-grasp | Notes |
247|-----------|-----------|-----------|-------|
248| Main server | 129 | 196 | ngit-relay uses supervisord |
249| Git HTTP protocol | 0 (C binary via fcgiwrap) | ~1,000 | ngit-grasp implements HTTP layer |
250| Auth logic (hooks) | 135 + 52 | 0 | ngit-grasp inline, no hooks |
251| Auth logic (inline) | 0 | ~800 | ngit-grasp authorization module |
252| Nostr relay policies | 186 | ~3,000 | Both use libraries (Khatru vs nostr-relay-builder) |
253| Git-only proactive sync | 112 + 305 | 0 | ngit-relay git sync only |
254| Nostr event proactive sync | 0 | ~5,000 | ngit-grasp adds full event sync (GRASP-02 v4) |
255| Purgatory coordination | 0 | ~2,000 | ngit-grasp event/git coordination |
256| Shared utils | 241 + 132 | ~4,000 | ngit-grasp more comprehensive |
257| Config | ~50 | ~400 | ngit-grasp CLI + validation |
258| Metrics | 0 | ~1,500 | ngit-grasp Prometheus |
259| **Total** | **~1,866** | **~25,000** | ngit-grasp 13x more code |
260
261**Why the difference?**
262- **Nostr event sync**: ngit-relay has NONE, ngit-grasp implements full multi-relay event sync (~5,000 lines)
263- **Git HTTP protocol**: ngit-relay uses C binary, ngit-grasp implements HTTP layer (~1,000 lines)
264- **Purgatory coordination**: ngit-grasp adds event/git coordination system (~2,000 lines)
265- **Metrics & observability**: ngit-grasp includes comprehensive monitoring (~1,500 lines)
266- Both use relay libraries (Khatru vs nostr-relay-builder), but ngit-grasp has more modular policies
267
268### Performance Characteristics (Estimated)
165 269
166| Metric | ngit-relay | ngit-grasp | Notes | 270| Metric | ngit-relay | ngit-grasp | Notes |
167|--------|-----------|-----------|-------| 271|--------|-----------|-----------|-------|
168| Startup | ~2-5s | ~0.5s | Fewer processes | 272| **Startup** | ~2-5s | ~0.5s | Single process vs multi-process |
169| Memory | ~150MB | ~75MB | Single process, no GC | 273| **Memory (Idle)** | ~150MB | ~75MB | No GC, single process |
170| CPU (idle) | ~1-2% | ~0.5% | Fewer processes | 274| **Memory (Active)** | ~200MB+ | ~100-150MB | Depends on event volume |
171| Push latency | +50-100ms | +10-20ms | No hook spawn overhead | 275| **CPU (Idle)** | ~1-2% | ~0.5% | Fewer processes |
172| Clone latency | ~same | ~same | Both passthrough to Git | 276| **Push Latency** | +50-100ms | +10-20ms | No hook spawn overhead |
173| Concurrent pushes | Good | Excellent | Tokio async vs goroutines | 277| **Clone Latency** | ~same | ~same | Both passthrough to git |
174| Event ingestion | Good | Excellent | Rust async + zero-copy | 278| **Concurrent Pushes** | Good (goroutines) | Excellent (tokio async) |
175 279| **Event Ingestion** | Good (Badger) | Excellent (LMDB zero-copy) |
176*Note: These are estimates. Actual performance depends on workload and hardware.* 280| **Sync Throughput** | Moderate (polling) | High (negentropy + async) |
177 281
178## Code Complexity 282*These are estimates based on architecture. Actual performance depends on workload.*
179
180### Lines of Code (Estimated)
181
182| Component | ngit-relay | ngit-grasp |
183|-----------|-----------|-----------|
184| Main server | ~150 | ~200 |
185| Git handlers | ~0 (C binary) | ~500 |
186| Auth logic | ~200 | ~300 |
187| Nostr relay | ~500 | ~100 (using library) |
188| Shared utils | ~300 | ~200 |
189| Config/setup | ~200 | ~100 |
190| **Total** | **~1,350** | **~1,400** |
191
192Similar complexity, but ngit-grasp has:
193- More Git protocol code (we implement it)
194- Less Nostr relay code (using library)
195- Less deployment code (no hooks/supervisord)
196 283
197## Migration Path 284## Migration Path
198 285
199For users of ngit-relay, migration to ngit-grasp would involve: 286For users of ngit-relay, migration to ngit-grasp involves:
200 287
2011. **Export data** from Badger to LMDB/NDB 288### Data Migration
2022. **Copy Git repositories** (same structure)
2033. **Update environment variables** (mostly compatible)
2044. **Change deployment** from Docker Compose to binary/Docker
2055. **Update URLs** if domain changes
206 289
207The **Nostr events** and **Git data** are compatible - only the server changes. 2901. **Events**: Export from Badger → Import to LMDB/NostrDB
291 - No direct migration tool yet (would need to be built)
292 - Alternative: Use proactive sync to re-fetch from other relays
2932. **Git Repositories**: Direct copy (same structure)
294 ```bash
295 cp -r /srv/ngit-relay/repos/* /path/to/ngit-grasp/data/git/
296 ```
2973. **Configuration**: Translate environment variables
298 - Most variables are compatible (`NGIT_DOMAIN`, etc.)
299 - Remove nginx/supervisord-specific configs
300
301### Compatibility
302
303- **Git Data**: 100% compatible (same repository structure)
304- **Nostr Events**: 100% compatible (standard NIP-34)
305- **HTTP URLs**: Compatible (same path structure)
306- **Git Hooks**: ngit-grasp doesn't use hooks (inline auth instead)
307
308### Downtime
309
310- Option 1: Run both in parallel (different domains), gradually migrate
311- Option 2: Short downtime for data copy + config update
208 312
209## When to Choose Each 313## When to Choose Each
210 314
211### Choose ngit-relay (Reference) if: 315### Choose ngit-relay (Reference) if:
212 316
213- ✅ You need a proven, production-tested implementation 317- ✅ You need proven, production-tested code
214- ✅ You're already familiar with Go 318- ✅ You're already familiar with Go ecosystem
215- ✅ You want to stay close to the reference 319- ✅ You prefer simple, minimal codebases (~1,866 lines)
216- ✅ You need to deploy immediately 320- ✅ You trust battle-tested C binaries (git-http-backend)
217- ✅ You prefer Docker Compose workflows 321- ✅ You want to stay close to the reference implementation
322- ✅ You need to deploy immediately without complexity
323- ✅ Your users will push events directly to your relay (no sync needed)
324- ✅ You only need git data sync, not Nostr event sync
218 325
219### Choose ngit-grasp (This Project) if: 326### Choose ngit-grasp (This Project) if:
220 327
328- ✅ **You need Nostr event sync from other relays** (the main differentiator)
221- ✅ You want better performance and lower resource usage 329- ✅ You want better performance and lower resource usage
222- ✅ You prefer Rust's type safety and ecosystem 330- ✅ You prefer Rust's type safety and memory safety
223- ✅ You want simpler deployment (single binary) 331- ✅ You want simpler deployment (single binary, no supervisord)
224- ✅ You want to contribute to a modern codebase 332- ✅ You need event/git data coordination (purgatory)
225- ✅ You're building on top of the GRASP protocol 333- ✅ You want inline authorization (lower latency)
226- ✅ You want inline authorization over hooks 334- ✅ You need comprehensive observability (Prometheus metrics)
227- ✅ You need better integration testing 335- ✅ You're comfortable with more complex codebase (~25,000 lines)
336- ✅ You want full GRASP-02 v4 multi-relay event discovery
228 337
229## Future Roadmap Comparison 338## Current Status
230 339
231### ngit-relay (Reference) 340### ngit-relay (Reference)
232- ✅ GRASP-01 complete 341- ✅ GRASP-01 complete and production-ready
233- 🔄 GRASP-02 in progress 342- ✅ Git data proactive sync (fetches from git servers)
234- ⏭️ GRASP-05 planned 343- ❌ No Nostr event sync (relies on client pushes)
235- ⏭️ NIP-42 auth-to-read 344- ✅ Battle-tested in production
236- ⏭️ NIP-70 protected events 345- 🔄 Community adoption growing
237- ⏭️ Spam prevention
238 346
239### ngit-grasp (This Project) 347### ngit-grasp (This Project)
240- 🔄 GRASP-01 in development 348- ✅ GRASP-01 complete with comprehensive testing
241- ⏭️ GRASP-02 planned (easier with Rust async) 349- ✅ GRASP-02 v4 multi-relay Nostr event sync with negentropy
242- ⏭️ GRASP-05 planned 350- ✅ Git data proactive sync (via purgatory queue)
243- ⏭️ Advanced caching strategies 351- ✅ Purgatory system for event/git coordination
244- ⏭️ Metrics and observability 352- ✅ Prometheus metrics and health tracking
245- ⏭️ Plugin system for custom policies 353- ✅ NIP-77 negentropy support
354- ✅ Full integration test suite
355- 🔄 Production deployment validation ongoing
246 356
247## Conclusion 357## Conclusion
248 358
249Both implementations are valid approaches to GRASP: 359Both implementations are valid approaches to GRASP with different philosophies:
360
361- **ngit-relay** prioritizes simplicity - clients push events, relay syncs git data (~1,866 lines)
362- **ngit-grasp** prioritizes completeness - syncs both events and git data from network (~25,000 lines)
363
364**The fundamental difference**: ngit-relay expects clients to push Nostr events to it. ngit-grasp proactively discovers and syncs events from other relays in the network.
250 365
251- **ngit-relay** is the mature, proven reference implementation 366The choice depends on your priorities:
252- **ngit-grasp** is a modern, performant alternative with better DX
253 367
254The choice depends on your priorities: stability vs. performance, familiarity vs. innovation, proven vs. cutting-edge. 368| Priority | Recommendation |
369|----------|---------------|
370| **Simplicity** | ngit-relay |
371| **Event Discovery** | ngit-grasp (syncs from network) |
372| **Production Stability** | ngit-relay (more battle-tested) |
373| **Event Completeness** | ngit-grasp (proactive sync) |
374| **Low Resources** | ngit-grasp (single binary, lower memory) |
375| **Quick Deploy** | ngit-relay (Docker Compose) |
376| **Development** | ngit-grasp (better tooling, type safety) |
377| **Network Resilience** | ngit-grasp (multi-relay sync) |
255 378
256For new deployments where performance and simplicity matter, **ngit-grasp** is the recommended choice. For production systems requiring maximum stability, **ngit-relay** is the safer bet until ngit-grasp reaches maturity. 379For deployments where **Nostr event sync** is important (discovering events from other relays), **ngit-grasp** is required. For simpler deployments where users will push events directly, **ngit-relay** is sufficient and battle-tested.