A push to refs/nostr/<event-id> is accepted before its PR event is known, and its objects went straight into the identifier family. The family is never garbage-collected, so anyone could fill permanent storage without signing anything, and an upload whose event never arrived stayed forever. Approach Route by what push authorization already decides. A ref named by a signed State or PR event, accepted or in purgatory, is received into the family as before. A refs/nostr ref with no event, or only a placeholder, is received into the view's own object directory. Pre-validation now reports whether a match was signed, because a placeholder match was indistinguishable from a stored event. Accepting a PR event first promotes its tip: fetch the history from the view into the family, check the family alone holds it down to existing retained roots, then install the usual retained and base roots. On failure the event is rejected and its placeholder kept, so the upload expires normally and the event can be sent again. While a view holds staged objects every push to it is staged, because the view advertises pending refs and a client may omit objects only staging holds. Signed tips of such a push are recorded as owed before Git runs and promoted when it finishes. Compaction refuses to run while anything is owed: rollback after a State deletion needs history no ref names, so a missing ref never proves history is disposable. Objects a view holds before it is first staged are moved into the family. Staging is reclaimed with git repack -a -d -l and git prune. Git can install a ref whose parent a concurrent repack removed (see tests/git_cruft_concurrency.rs), so compaction takes the family write lease that every push already holds. It waits at most 250ms and retries with backoff. One worker handles requests from pushes, promotions and ref deletions, and reads the persistent registry at startup. The /prs/ handler now releases the family lease before post-push processing, as the standard handler does. Promotion of a waiting PR event re-enters the family and would otherwise deadlock. Assumptions - Views and their family are on one filesystem; moving pre-existing objects uses hard links. - Retained roots are complete. A damaged root fails promotion and is left to the integrity pass. - One server process per storage root, as the family lease already assumes. Excluded - Storage quotas. Staging bounds how long an unsigned upload is kept, not its size. - A pack from a signed push is stored whole. A signer can make any object reachable from their own tip, so filtering it would protect nothing. - Fetches take no lease. A fetch of a pending ref that expires while being served may fail. - Archives store a view as it is; restoring one imports staged objects. - State acceptance, rollback and purgatory sync are unchanged. Validation - nix develop -c cargo test --lib git::staging: 13 passed, covering reclamation, a pending sibling keeping its history, promotion, refusal of incomplete history, owed history surviving ref deletion, restart recovery and a busy family. - nix develop -c cargo test --test pending_upload_staging: 4 end-to-end tests passed, including an unsigned upload across a relay crash and a signed push that omits objects only staging holds. - cargo clippy --workspace --all-targets -- -D warnings and cargo fmt --check were clean. Assisted-by: Claude Fable 5.1
ngit-grasp Documentation
Welcome to the ngit-grasp documentation! We use the Diátaxis framework to organize our documentation into four types, each serving a different purpose.
PRACTICAL THEORETICAL
───────── ───────────
LEARNING │ Tutorials │ Explanation │
│ │ │
│ Getting │ Architecture │
│ Started │ Decisions │
│ │ │
├────────────────┼──────────────────┤
│ │ │
WORKING │ How-To │ Reference │
│ Guides │ │
│ │ API Docs │
│ Deployment │ Protocols │
│ Testing │ │
│ │ │
📚 Documentation Types
🎓 Tutorials - Learning by Doing
Purpose: Learn the basics through practical steps
For: Newcomers getting started
Style: Step-by-step lessons with guaranteed outcomes
- Getting Started - Your first ngit-grasp setup
- Running Your First Audit - Using grasp-audit tool
🔧 How-To Guides - Solving Problems
Purpose: Accomplish specific tasks
For: Users with basic knowledge solving real problems
Style: Practical recipes and solutions
- Deploy ngit-grasp - Choose Docker, NixOS, Linux, Proxmox, or managed hosting
- Deployment contract - Shared runtime and persistence requirements
- Configure Nix Flakes - Nix development environment
- Run Compliance Tests - GRASP compliance testing
- Upgrade nostr-sdk - Handling SDK upgrades
📖 Reference - Technical Information
Purpose: Look up technical details
For: Users who know what they're looking for
Style: Dry, factual, comprehensive
- Git Protocol - Git Smart HTTP protocol details
- GRASP Protocol - GRASP specification details
- Configuration - All config options
- API Reference - Internal API documentation
💡 Explanation - Understanding Concepts
Purpose: Understand the "why" and design decisions
For: Users wanting deeper understanding
Style: Discussion, context, alternatives
- Architecture Overview - System design and components
- Inline Authorization - Why we chose this approach
- Administration Vision - Nostr-authenticated management, embedded UI, and runtime configuration
- Comparison with ngit-relay - How we differ from reference
- Design Decisions - Key architectural choices
🚀 Quick Start Paths
I'm brand new to ngit-grasp
- Read README.md for project overview
- Follow Getting Started Tutorial
- Understand Architecture Overview
I want to deploy ngit-grasp
- Review Configuration Reference
- Choose an environment in Deploy ngit-grasp
- Verify the deployment and test its backup
I want to develop on ngit-grasp
- Follow Getting Started Tutorial
- Read Architecture Overview
- Check Nix Flakes How-To
- Review Test Strategy
I want to understand the design
- Read Inline Authorization Explanation
- Review Design Decisions
- Compare with ngit-relay Comparison
I'm looking for specific information
- Protocol details? → Reference
- Configuration options? → Configuration Reference
- Git protocol? → Git Protocol Reference
📂 Additional Resources
Learnings
DEPRECATED - Being migrated to Diátaxis structure:
- Gotchas → How-To Guides
- Patterns → Reference or Explanation
- Notes → Appropriate category
🤝 Contributing to Documentation
When adding documentation, ask yourself:
Is it a tutorial?
- Does it teach a beginner?
- Is it a complete lesson with guaranteed outcome?
- → Add to
tutorials/
Is it a how-to guide?
- Does it solve a specific problem?
- Is it a recipe for accomplishing a task?
- → Add to
how-to/
Is it reference material?
- Is it technical information?
- Will people look it up when needed?
- → Add to
reference/
Is it explanation?
- Does it explain "why"?
- Does it discuss alternatives or design?
- → Add to
explanation/
See Diátaxis documentation for more guidance.
📊 Project Status
ALPHA - Under active development. Core functionality working, API may change.
Completed
- ✅ grasp-audit compliance testing tool
- ✅ Nix flake development environment
- ✅ nostr-sdk 0.43 upgrade
- ✅ Documentation restructure (Diátaxis)
In Progress
- 🔄 Core ngit-grasp server implementation
- 🔄 GRASP-01 compliance
Planned
- 🔜 GRASP-02 (Proactive Sync)
- 🔜 GRASP-05 (Archive)
🔗 External Links
Documentation structure based on Diátaxis
Last updated: November 4, 2025