libnoa 0.1.1

AI-native distributed version control system with per-agent workspace isolation, JSONL append-only logs, snapshot-based history, and full git protocol compatibility
Documentation
# تصميم تخزين الكائنات

## نظرة عامة

يستخدم noa نموذج تخزين معنون بالمحتوى مستوحى من Git ولكن مع بنية خلفية قابلة للتوصيل. تُعنون الكائنات بتجزئة SHA-256 وتُخزن كـ blobs غير شفافة.

## أنواع الكائنات

### Blob

محتوى ملف خام. يُعرف بـ `SHA256(content)`.

```rust
pub struct BlobId(pub String); // SHA-256 بترميز hex
```

لا يوجد ضغط دلتا. كل محتوى فريد ينتج blob واحدًا بالضبط. المحتوى المكرر يُلغى تكراره تلقائيًا بواسطة التجزئة.

### Tree

قائمة مجلد. تعين المسارات إلى مدخلات فرعية (blobs أو أشجار فرعية).

```rust
pub struct TreeEntry {
    pub name: String,
    pub kind: TreeEntryKind, // Blob أو Tree
    pub hash: String,        // SHA-256 للفرع
}

pub struct TreeId(pub String); // SHA-256(msgpack(entries))
```

تُسلسل الأشجار باستخدام MessagePack للاكتناز وسرعة إلغاء التسلسل.

## تعريف الواجهة (Trait)

```rust
#[async_trait]
pub trait ObjectStore: Send + Sync {
    async fn put_blob(&self, data: &[u8]) -> Result<BlobId>;
    async fn get_blob(&self, id: &BlobId) -> Result<Vec<u8>>;
    async fn put_tree(&self, entries: Vec<TreeEntry>) -> Result<TreeId>;
    async fn get_tree(&self, id: &TreeId) -> Result<Vec<TreeEntry>>;
}
```

## الخلفيات

### RedbObjectStore (محلي)

يستخدم مخزن المفاتيح-القيمة المدمج [redb](https://github.com/cberner/redb).

- جدولان: `blobs` (المفتاح: بايتات التجزئة، القيمة: بايتات المحتوى) و
  `trees` (المفتاح: بايتات التجزئة، القيمة: مدخلات msgpack)
- قراءات بدون نسخ عبر ملفات معينة بالذاكرة
- معاملات ACID مع استرداد تلقائي من الأعطال
- كاتب واحد، قراء متعددون عبر MVCC
- لا حاجة لخادم خارجي

### MinioObjectStore (عن بُعد)

يستخدم API متوافق مع S3 عبر `aws-sdk-s3`.

- عنونة بنمط المسار: `<bucket>/blobs/<hash>`، `<bucket>/trees/<hash>`
- يدعم أي خلفية متوافقة مع S3 (MinIO, AWS S3, GCS، إلخ)
- إعادة محاولة تلقائية مع تراجع أسي (exponential backoff)
- مناسب للنشر الموزع

## قرارات التصميم

### لماذا SHA-256 بدلاً من SHA-1؟

يستخدم Git خوارزمية SHA-1، وهي مكسورة تشفيريًا (هجوم SHAttered، 2017). SHA-256 مقاومة للتصادم ومتاحة على نطاق واسع.

### لماذا لا يوجد ضغط دلتا؟

1. **البساطة**: يضيف ضغط الدلتا (ملفات pack في Git) تعقيدًا كبيرًا
   (مطابقة النوافذ المنزلقة، thin packs، سلاسل الدلتا).
2. **أداء الكتابة**: كتابات blob المباشرة هي O(1). ضغط الدلتا
   يتطلب قراءة كائنات موجودة.
3. **حمل عمل وكيل الذكاء الاصطناعي**: الوكلاء يعيدون توليد ملفات كاملة بشكل متكرر.
   الإصدارات القديمة مؤقتة — سلاسل الدلتا ستكون قصيرة ومتعددة.
4. **تفريغ الخلفية**: S3/MinIO يتوليان إلغاء التكرار في طبقة التخزين.

### لماذا MessagePack للأشجار؟

- أصغر بنسبة 30-50% من JSON للبيانات الثقيلة بالثنائيات
- مرونة في المخطط (لا حاجة لتعريفات protobuf)
- دعم نظام Rust البيئي عبر `rmp-serde`
- إلغاء تسلسل سريع

### لماذا redb بدلاً من SQLite؟

- **أمان الأنواع**: يستخدم redb أنواع Rust العامة لتعريفات الجداول
- **الأداء**: redb مُحسَّن لأحمال عمل Rust (قراءات بدون نسخ)
- **البساطة**: اعتمادية واحدة، لا ربط بمكتبة C
- **أمان الأعطال**: سجل الكتابة المسبقة (WAL) في redb أبسط من وضع WAL في SQLite

مقايضة: redb لديه مجتمع أصغر وخيارات أدوات أقل من SQLite. بالنسبة لحالة استخدام noa (تخزين ثنائي مدمج)، المقايضة مواتية.