Files
ngit-grasp/docs/explanation
DanConwayDev d3d905010c fix(grasp06): narrow /prs/ per-path lock, gate cleanup on in-flight count
The previous design held the per-(submitter, identifier) mutex for the
entire receive-pack pipeline — `git init --bare`, the pack upload from
the client, `git-receive-pack`, per-ref validation, and the zero-ref
cleanup. Two concurrent pushes to the same `/prs/<submitter>/<id>.git`
path were therefore fully serialised end-to-end, with the second push's
HTTP connection blocked on the mutex for the entire duration of the
first push (including its pack upload over the wire). With multiple
agents or CI jobs sharing a contributor identity this could produce
HTTP/proxy timeouts and apparently-stuck pushes for no good reason —
git's own ref locking would normally handle intra-push concurrency on
the same path just fine.

Switch to a `PrsPathState { mu: Mutex<()>, in_flight: AtomicUsize }`
per path. The receive handler now takes the mutex only briefly:

  * at the start of the request to run `git init --bare` and bump
    `in_flight` from 0 to 1, then release the mutex,
  * at the end of the request to drop `in_flight` and, if it lands on
    zero with the repo at zero refs, `rm -rf` the bare directory.

`git-receive-pack` and per-ref validation run with no per-path lock
held, so concurrent pushes by different agents to the same path proceed
in parallel.

Off-push cleanup paths (the PR-event policy when it discards a scoped
placeholder whose incoming event mismatches, and the purgatory expiry
sweep when a scoped placeholder times out) take the same mutex briefly,
delete the dangling ref, then remove the bare directory only when
`in_flight.load() == 0` and `list_refs` is empty. With both reads
performed under the mutex that gates `in_flight` mutations, a repo
deletion can never race a push that is mid-receive: either the push is
still in init/register and we wait on the mutex, or the push has
already incremented `in_flight` (so we read non-zero and skip), or the
push has finished and decremented (so the directory is genuinely idle).

The end-of-push cleanup now also runs when receive-pack returns a
protocol-error response (200 with ERR pkt-line), which the previous
code's early-return skipped — a probe push that failed git-level
validation after `ensure_repo_initialised` had created the directory
used to leak an empty `.git` dir, which now gets removed in the same
critical section.

A small `path_state(&locks, path)` helper centralises the
get-or-insert-Arc dance the three sites used to duplicate.

Docs updated:

  * docs/explanation/grasp-06-contributor-pr-submission.md — replace
    the "lock held for the entire push pipeline" paragraph with the
    new mutex + `in_flight` discipline; update the three-sites
    enumeration to describe the `in_flight == 0` guard.
  * docs/explanation/architecture.md — same shape, one-paragraph.
  * docs/how-to/enable-grasp-06.md — call out that the mutex is held
    only briefly so concurrent pushes don't serialise.
2026-05-15 19:15:42 +00:00
..

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


Deletion Requests

Handling repository and event deletion

Topics:

  • Deletion request architecture
  • Delete disrespector concept
  • Preventing left-pad scenarios
  • Archival policies

Read when: You want to understand how ngit-grasp handles deletion events (planned feature)


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

  1. Read to understand - Not to accomplish a task
  2. Follow your curiosity - Read what interests you
  3. Connect concepts - Link ideas together
  4. Question and explore - Think critically

Not sure if this is what you need?


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.