Production logs after deploying a8964bb to gitnostr.com showed ~41
incomplete negentropy retries and 20 batches completing with partial
results within six minutes, some batches missing hundreds of events.
Negentropy reconciliation identifies event IDs missing locally, but a
relay's exact-ID response can return only a subset (or nothing on the
retry). Batches without repository/root-event metadata - the generic
Layer 1 announcements batch - cannot build a semantic REQ+EOSE
fallback, so handle_eose finalized them "with partial results" and
dropped the missing IDs entirely. Nothing retried them until the next
daily sync up to 25 hours later, leaving repository announcements and
their dependencies absent indefinitely.
Missing IDs from a batch that finalizes incomplete are now registered
in a per-relay recovery index (sync::missing_events), and the existing
sync maintenance timer refetches them over the relay's live connection
with bounded exponential backoff (30s doubling to 15min, one in-flight
attempt per relay, 300 IDs per fetch). Network I/O runs outside the
sync actor lock. Startup remains non-blocking: the batch still
finalizes as failed, the relay transitions to
ConnectedHistoricSyncFailures, and traffic is served while recovery
runs in the background.
Semantics:
- progress clears only the IDs actually recovered and resets backoff;
- duplicate incomplete responses merge into the pending set without
duplicating work;
- IDs satisfied by live sync or user submission are cleared on the
next tick without consuming attempt budget;
- attempts against a disconnected relay are deferred, not counted, so
an unavailable relay neither expires its work nor loops tightly;
- 12 consecutive zero-progress attempts expire the pending IDs with an
explicit warning; the relay stays observably degraded until the
daily sync re-discovers the gap;
- full recovery promotes the relay back to Connected unless an
unrelated batch failure was observed for it;
- nothing persists across restarts: historic sync re-runs from scratch
and re-detects any still-missing events, so incomplete work is never
falsely reported as complete.
Also fixes the retry-subscription-failure path, which confirmed an
incomplete batch without marking it failed (falsely reporting
Connected), and bounds the previously unbounded missing_ids log arrays
to a five-ID sample.
Regression coverage: a new censoring WebSocket proxy fixture sits
between a syncing relay and a real ngit-grasp bootstrap relay,
forwarding NIP-77 frames unchanged while withholding chosen EVENT
frames. The integration test reproduces the full production sequence
(subset response, zero-progress retry, no semantic fallback,
ConnectedHistoricSyncFailures) and proves the withheld event is
recovered and the relay promoted to Connected once the event becomes
available - without a restart and while live sync continues unstarved.
Unit tests cover registration dedupe, partial clears, backoff growth
and cap, explicit expiry, deferral, and health-restoration poisoning.
Full cargo test suite passes.
tokio-tungstenite was added as a dev-dependency for the proxy fixture;
it was already present transitively in Cargo.lock, so no Nix hash
updates are required (crates.io dependency under cargoLock).
Deliberately out of scope: durable persistence of pending recovery
work, retrying missing IDs against other relays, outbound-target
policy changes, and broader logging cleanup.
Confirms the closed issue
nostr:nevent1qqs94up6nnkzjlz4fcy5tesh8yxvr63xqjhg79etmc573fuunjt0qeqpz3mhxue69uhhyetvv9ujumn8d96zuer9wc5tdht6
Explanation
Understanding-oriented documentation - Concepts, design decisions, and the "why" behind ngit-grasp.
What Is Explanation?
Explanation documentation helps you understand concepts and design decisions, providing context and discussing alternatives.
Characteristics:
- ✅ Understanding-oriented (clarify concepts)
- ✅ Theoretical (ideas and design)
- ✅ Discuss alternatives
- ✅ Provide context and background
- ✅ Answer "why" questions
Not explanation:
- ❌ Step-by-step lessons (those are Tutorials)
- ❌ Problem-solving recipes (those are How-To)
- ❌ Technical specifications (those are Reference)
Available Explanation Documentation
Architecture Overview
Understand the system design and component interaction
Topics:
- Overall architecture
- Component responsibilities
- Data flows
- Technology choices
- Design patterns
Read when: You want to understand how ngit-grasp works as a system
Inline Authorization
Why we validate pushes inline instead of using Git hooks
Topics:
- The authorization problem
- Git hooks approach
- Inline approach
- Comparison and trade-offs
- Implementation details
Read when: You want to understand the core architectural decision
Design Decisions
Key architectural choices and their rationale
Topics:
- Inline authorization vs hooks
- Technology stack choices
- Storage design
- API design
- Performance considerations
Read when: You want to know why things are the way they are
Comparison with ngit-relay
How ngit-grasp differs from the reference implementation
Topics:
- Architecture comparison
- Component differences
- Trade-offs
- Migration path
- Compatibility
Read when: You're familiar with ngit-relay and want to understand differences
Purgatory Design
In-memory holding area for events awaiting git data
Topics:
- The "which arrives first?" problem
- Separate storage for state vs PR events
- Late binding for state events
- Bidirectional waiting for PR events
- Authorization during push
Read when: You want to understand how ngit-grasp handles out-of-order event/git data arrival
GRASP-02 Proactive Sync
Relay-to-relay synchronization for repository discovery
Topics:
- Negentropy-based event sync
- Repository announcement discovery
- Relay management and reconnection
- Layer 2 filtering
- Bootstrap and dynamic relay discovery
Read when: You want to understand how ngit-grasp discovers and syncs repositories across relays
GRASP-02 Purgatory Git Data Fetching
Proactive git data fetching from remote servers
Topics:
- Identifier-based batching
- Exponential backoff with fresh start
- Domain throttling (5 concurrent, 30/min)
- Debounced delays (3min user, 500ms sync)
- 30-minute expiry
- Mock-based testability
Read when: You want to understand how purgatory automatically fetches missing git data
Unified Git Data Sync
Shared processing for git push and purgatory sync paths
Topics:
- Why unify push and sync processing
- OID syncing to owner repos
- Ref alignment logic
- Event release from purgatory
- WebSocket notification
Read when: You want to understand how git data is processed consistently regardless of arrival method
Monitoring Overview
Prometheus metrics and observability
Topics:
- Metrics philosophy
- Connection tracking
- Git operation metrics
- Nostr event metrics
- Privacy considerations
Read when: You want to understand how to monitor ngit-grasp in production
Defensive Measures & Rate Limiting
Protection against abuse, spam, and denial-of-service attacks
Topics:
- Connection and subscription management
- Event publishing rate limits
- Content filtering (blacklists/whitelists)
- Event validation plugin system (WritePolicy/QueryPolicy)
- Relay health management (naughty list, exponential backoff)
- Privacy-preserving IP tracking
- Future enhancements (per-IP rate limiting)
Read when: You want to understand how ngit-grasp protects against abuse and what defensive features are available
GRASP-05 Archive Mode
Read-only mirroring of repositories
Topics:
- Archive whitelist configuration
- Archive-all mode
- Read-only mode defaults
- Use cases for backup/mirror relays
Read when: You want to understand how to run an archive/backup relay
Repository Lifecycle
Handling repository removal, holding, archive, recovery, and purgatory
Topics:
- Repository lifecycle architecture
- Delete disrespector concept
- Preventing left-pad scenarios
- Archival policies
- Holding, recovery, purgatory, and operator curation flows
Read when: You want to understand how ngit-grasp keeps nostr state and git data aligned across deletion, vanish, moderation, recovery, and purgatory flows
Planned Explanation Documentation
GRASP Protocol Design
Status: 🔜 Planned
Topics:
- Why Nostr for Git?
- Authorization model
- Trust and verification
- Decentralization benefits
Storage Architecture
Status: 🔜 Planned
Topics:
- Why separate Git and Nostr storage?
- Indexing strategy
- Performance considerations
- Scaling approach
Testing Philosophy
Status: 🔜 Planned
Topics:
- Why test isolation?
- Integration vs unit tests
- Compliance testing approach
- Test-driven development
Performance Considerations
Status: 🔜 Planned
Topics:
- Async architecture
- Caching strategy
- Database choices
- Bottlenecks and solutions
How to Use Explanation Documentation
- Read to understand - Not to accomplish a task
- Follow your curiosity - Read what interests you
- Connect concepts - Link ideas together
- Question and explore - Think critically
Not sure if this is what you need?
- Want to learn by doing? → Tutorials
- Need to solve a problem? → How-To Guides
- Looking for technical details? → Reference
Contributing Explanation Documentation
When writing explanation:
DO:
- ✅ Discuss concepts and ideas
- ✅ Provide context and background
- ✅ Explain alternatives
- ✅ Use analogies and examples
- ✅ Connect to broader context
- ✅ Answer "why" questions
DON'T:
- ❌ Provide step-by-step instructions (link to Tutorials/How-To)
- ❌ List technical details (link to Reference)
- ❌ Assume you must be comprehensive
- ❌ Avoid opinions (explanation can be opinionated)
Template:
# Explanation: [Topic]
**Purpose:** [What concept/decision this explains]
**Audience:** [Who wants to understand this]
---
## The Problem/Question
[What are we trying to understand?]
---
## Background
[Context and history]
---
## Our Approach
[How we address it]
### Why This Works
[Explanation of benefits]
### Trade-offs
[What we gain and lose]
---
## Alternatives Considered
### [Alternative 1]
**Pros:**
- [Benefits]
**Cons:**
- [Drawbacks]
**Why we didn't choose it:**
[Reasoning]
---
## Conclusion
[Summary of understanding]
---
## Related Documentation
- [Links to relevant docs]
See Diátaxis: Explanation for detailed guidance.
Part of the ngit-grasp documentation using the Diátaxis framework.