# سجل التغييرات

كل التغييرات المهمة في صباربيز. يتبع السجل صيغة Keep a Changelog، ويستخدم المشروع Semantic Versioning، وفي إصدار من السلسلة 0.x يعني ذلك أن الواجهة قد تتغير بين إصدار وآخر.

النسخة المعلنة حاليًا 0.5.13. تبقى بنود الإصدارين 0.1.0 و0.2.0 بنطاقها الأصلي. نتائج CI والآلة الافتراضية المحلية محددة بنطاقها وتاريخها، ولم تثبت الجاهزية للإنتاج أو التشغيل على خادم مستقل. يعرض [مرجع الحالة](https://base.sbarah.com/docs/reference/status/) النطاق الحالي، وتبقى البنود المؤرخة أدناه سجلًا لتغييراتها.

## [لم يُصدر بعد]

### ما زال مفتوحًا

- **حذف البيئة لا يعمل في التثبيت العادي.** يُرد عليه دائمًا بـ`409` ومعه "Exact ownership inventory unavailable"، ولا يتغير شيء، فلا سبيل إلى الاستعادة ولا إلى الإزالة النهائية كذلك. فالتجهيز لا يسجّل أبدًا القائمة الدقيقة لموارد البيئة، وليس لعنقود PostgreSQL المشترك ولا لعملية Storage المشتركة بعدُ فحصٌ يجعل هذه القائمة صادقة. كان [مرجع API](https://base.sbarah.com/docs/reference/api/) يقول إن الحذف "قد" يُرد عليه بـ`409`، وصار يقول إنه يُرد عليه كذلك دائمًا، واختبارٌ يثبّت السلوك الحالي.

## الإصدار [0.5.13]، 2026-10-19

### أُصلح

- لم يعد تسجيل الخروج من لوحة التحكم يُنهي رموز الوصول. فاللوحة تُخرجك تلقائيًا أيضًا حين تنتهي جلستك، فكان وصول الوكيل عبر MCP أو `/v1` قد يتوقف بـ`401` دون أن يفعل أحد شيئًا. صار الرمز ينتهي فقط كما يقول دليل الوكلاء: حين يُلغى أو تنتهي صلاحيته، أو عند إعادة تعيين كلمة المرور أو استعادة عامل المصادقة، أو حين تتغير سياسة المصادقة الثنائية. أما الرمز الذي توقف بهذه الطريقة من قبل فيبقى متوقفًا، فأنشئ رمزًا جديدًا.

## الإصدار [0.5.12]، 2026-10-19

### أُصلح

- صار Studio الذي فُتح قبل الترقية إلى 0.5.11 يعود للعمل وحده بعدها أيضًا: عند أول إعادة تشغيل لا يكون سجل الاستخدام موجودًا بعد، فيُعتمد وقت آخر طلب للجلسة من لوحة الإدارة.

## الإصدار [0.5.11]، 2026-10-19

### أُصلح

- **لا وميض لصفحة الدخول.** إن كان الدخول محفوظًا، تنتظر لوحة الإدارة على شاشة محايدة ريثما يتحقق منه عميل Auth، بدل أن تعرض صفحة الدخول لحظةً ثم اللوحة. وإن لم يكن محفوظًا، تظهر صفحة الدخول فورًا.
- **يبقى Studio مفتوحًا ما دام مستخدمًا.** تتجدد جلسة Studio وحدها ما دامت صفحته ترسل طلبات. وتنتهي بعد ثماني ساعات دون أي طلب، أو بعد سبعة أيام من فتحها من لوحة الإدارة. ويبقى تسجيل الخروج أو تغيير كلمة المرور أو فقدان الدور منهيًا لها فورًا ([Studio](https://base.sbarah.com/docs/guides/studio/)).
- **يعود Studio بعد إعادة التشغيل.** بعد إعادة التشغيل أو الترقية، يعود Studio الذي استُخدم في آخر ثماني ساعات للعمل، بعد تأكيد الترقية. وتعرض الصفحة المفتوحة "Studio is starting" ثم تُحدّث نفسها وتكمل.

## الإصدار [0.5.10]، 2026-10-19

### إصلاحات

- **صار بإمكان تثبيت Docker ضبط عنوان Studio العام.** صارت `compose.yaml` و`deploy/compose.sh` وفحص المضيف تمرّر `SBARBASE_STUDIO_HOST`؛ وكانت حاوية لوحة الإدارة لا تستقبله أبدًا ([Studio](https://base.sbarah.com/docs/guides/studio/)).

## الإصدار [0.5.9]، 2026-10-19

### أُصلح

- **محرر SQL وصفحة Edge Functions في Studio.** صارت استعلامات SQL المحفوظة في مجلد داخل جلسة Studio بدل أن تفشل برسالة "SNIPPETS_MANAGEMENT_FOLDER env var is not set"، وتعرض صفحة Edge Functions الشيفرة المنشورة لكل دالة، منسوخةً عند فتح Studio.
- **يستطيع Studio تعديل ما أنشأته ملفات الترحيل.** يعمل Studio بحساب المطوّر الخاص بالبيئة، كما يعمل Studio على Supabase بحساب `postgres` الخاص بالمشروع: يعدّل الجداول والسياسات وأمان الصفوف، ويرى مخططات المطوّر وVault وسجل الترحيلات. وما ينشئه يملكه الحساب نفسه ([Studio](https://base.sbarah.com/docs/guides/studio/)).
- **يُكشف مسار Studio المحجوب.** عند فتح Studio يُفحص مساره إلى Auth وStorage من داخل Studio لا من الخادم، ويذكر الجدار الناري إن كان المسار محجوبًا. ويعرض دليل نشر الخادم قاعدتي الجدار الناري الضيقتين اللازمتين ([نشر الخادم](https://base.sbarah.com/docs/guides/server-deployment/#الجدار-الناري-مساران-من-الحاويات-إلى-الخادم)).

## الإصدار [0.5.8]، 2026-10-19

### أُضيف

- **إعداد واحد لعنوان Studio العام.** الأمر `lab/studio_address.py plan DOMAIN` يعرض ما تجهّزه مرة واحدة (سجل DNS شاملًا وشهادة تغطيه والإعداد)، والأمر `apply DOMAIN` يكتب `SBARBASE_STUDIO_HOST` للوحة الإدارة ولوكيل TLS ويعيد تشغيلهما، والأمر `verify DOMAIN` يخبرك أي خطوة ناقصة. وصار وكيل TLS يقرأ `SBARBASE_STUDIO_HOST` حين لا يكون معه الخيار `--studio-host`، فيكفي ملف إضافي واحد للاثنين. وبعد ذلك يفتح كل مشروع جديد Studio دون أي عمل في DNS أو الشهادات ([Studio](https://base.sbarah.com/docs/guides/studio/)).

### تغييرات

- صار تنبيه لوحة الإدارة على خادم بلا عنوان Studio عام يسمّي هذا الإعداد بدل أن يذكر المتغير فقط.

### إضافات

- **تستطيع البيئة إنشاء مخططاتها الخاصة واستخدام Vault.** صار حساب المطوّر، الذي يستخدمه الوصول المباشر إلى قاعدة البيانات والوكلاء، يستطيع إنشاء مخططات خاصة به وتغيير أسمائها، فتعمل الترحيلات التي تضع شيفرتها خارج `public` (مثل `create schema app`) كما في Supabase، وكذلك `supabase db push`. وتبقى الأسماء التي تستخدمها المنصة مرفوضة (`auth` و`storage` و`extensions` و`realtime` و`vault` و`cron` و`net` و`graphql`، وكل اسم يبدأ بـ `supabase` أو `sbarbase`)، بحماية لا يستطيع الحساب حذفها ولا إيقافها. ويُثبَّت Vault في كل بيئة بالصلاحيات التي يعطيها Supabase لـ `postgres` و`service_role`، دون حق إعطائها لغيره، وتتشارك بيئات الخادم مفتاحه الجذري. وصار منشور `supabase_realtime` موجودًا دائمًا ويملكه الحساب، فتستطيع الترحيلات إضافة جداول إليه كما في Supabase. وصارت الإضافات التي تصل إلى شبكة الخادم أو ترى كل البيئات، مثل `http` و`pg_net` و`dblink` و`postgres_fdw` و`pg_stat_statements` و`pgroonga` (التي تستطيع كتابة ملفات في أي مكان على الخادم)، مرفوضة لحساب البيئة، وكانت supautils في الصورة تنشئها له. للبيئة التي يعمل فيها الوصول من قبل، أوقفه ثم شغّله مرة واحدة ([الاتصال بقاعدة البيانات](https://base.sbarah.com/docs/guides/database-access/)).

### إصلاحات

- **إيقاف الوصول إلى قاعدة البيانات وتشغيله يحفظ الصلاحيات الافتراضية التي ضيّقها ترحيل.** كان كل تشغيل للوصول يعيد منح الصلاحيات الافتراضية للواجهة لـ `anon` و`authenticated` و`service_role`، فيُلغي ترحيلًا سحبها، مثل صلاحية تنفيذ الدوال الجديدة. صارت تُمنح مرة واحدة، في أول مرة ([الاتصال بقاعدة البيانات](https://base.sbarah.com/docs/guides/database-access/)).

### تغييرات

- **مظهر جديد للوحة الإدارة.** صارت الألوان والمسافات والمكونات على رموز تصميم Supabase، ولكل شاشة بيئة إجراء رئيسي واحد، وفحص للتباين يحرس الألوان (طلب الدمج 18).

## الإصدار [0.5.7]، 2026-10-19

### إصلاحات

- **يفتح Studio خلف وكيل TLS.** يضغط Studio صفحاته. وكان وكيل Studio في لوحة الإدارة ووكيل TLS يتركان `fetch` في Bun يفك الضغط مع إبقاء ترويسة `content-encoding`، فتصل القفزة التالية بيانات غير مضغوطة موسومة بأنها gzip فيفشل فكها (وكان Cloudflare يعرض الخطأ 520). صار الوكيلان يمرران بيانات Studio وترويستها معًا.

## الإصدار [0.5.6]، 2026-10-19

### إصلاحات

- **لا مزيد من تسجيل الخروج بعد غياب ساعة.** ينتهي رمز الوصول في لوحة الإدارة بعد ساعة، وكان أي طلب به بعد انتهائه يسجّل خروجك ويحذف الجلسة من الخادم مع أنها قابلة للتجديد. صارت اللوحة تجدّد الرمز وتعيد الطلب مرة واحدة، ولا تُخرجك إلا إذا رُفض التجديد.

## الإصدار [0.5.5]، 2026-10-19

### إصلاحات

- **لا مزيد من تبويب Studio الذي لا يكتمل تحميله.** على خادم لم يُعط Studio عنوانًا عامًا، كان فتح اللوحة من العنوان العام للوحة الإدارة يترك تبويبًا يعرض "Starting Supabase Studio" بلا نهاية. صارت لوحة الإدارة تعرف ذلك من حالة Studio قبل أن تفتح شيئًا، فتعرض خطوات نفق SSH ولا تفتح أي تبويب، والتبويب الذي فُتح مسبقًا لمشروع جديد يشرح ما حدث ثم يُغلق ([Studio](https://base.sbarah.com/docs/guides/studio/)).

### تغييرات

- **صارت لوحة الإدارة بشكل Supabase ووضوحها.** تستخدم كل الصفحات رموز ألوان Supabase نفسها وشكل أزرارها وحقولها وبطاقاتها وتنبيهاتها وشاراتها وجداولها، مع حدود أوضح فلم تعد الأقسام والحقول والأزرار تذوب في رمادي واحد. الإجراء الرئيسي في الشاشة هو الزر الأخضر المصمت الوحيد، والقيم للقراءة فقط مثل الرموز والأوامر تبدو مختلفة عن الحقول التي تكتب فيها، والمفتاح أو الرمز الجديد يظهر في لوحة بإطار أخضر، وحلقة التركيز واضحة في الوضعين. يحقق النص وحدود العناصر مستوى WCAG AA في الوضعين الفاتح والداكن، ويفحص ذلك `tests/ui-contrast.test.ts`. لم تتغير المسارات ولا التسميات ولا السلوك ([تصميم لوحة الإدارة](https://base.sbarah.com/docs/reference/console-design/)).
- **تبقى مسجلًا في لوحة الإدارة ثلاثين يومًا.** صار الافتراضي لـ `SBARBASE_MANAGEMENT_SESSION_SECONDS` هو 2592000 بدل 43200، فلم يعد تسجيل الدخول ينتهي بعد اثنتي عشرة ساعة. لإعادة السلوك القديم اضبط قيمة أصغر ([الإعدادات](https://base.sbarah.com/docs/reference/configuration/)).

## الإصدار [0.5.4]، 2026-10-18

### تغييرات

- **التثبيت عبر Docker هو المسار الأول.** يبدأ دليل Docker من خادم Ubuntu 26.04 فارغ: الحزم `docker.io` و`docker-compose-v2` و`docker-buildx` من التوزيعة، ثم النسخ والفحص والتشغيل وإنشاء أول مشغّل، مع تنبيه بانتظار لوحة الإدارة قبل إنشاء المشغّل ([التثبيت عبر Docker](https://base.sbarah.com/docs/guides/docker/)). يعرض قسم التثبيت في الموقع هذه الأوامر الخمسة، ويبقى البدء السريع عبر systemd متاحًا برابط "من دون Docker". جرّبه `lab/vm-docker-rehearsal.sh` على آلة افتراضية محلية ونجحت 14 فحصًا ([دليل التجربة](https://github.com/M7MMAD-OMAR/sbarbase/blob/main/docs/evidence/vm-docker-install-checks.json))، ولم يُجرَّب بعد على خادم حقيقي.

### الأمان

- **خرجت Edge Functions من شبكة التشغيل المشتركة.** لا تصل حاوية Functions في كل بيئة إلا إلى Auth وREST الخاصين بها عبر شبكة تلك البيئة، وإلى Storage عبر منفذ على الخادم يثبّت مستأجر البيئة، فلا تصل دوال بيئة إلى خدمات بيئة أخرى ([FUNCTIONS-NETWORK-ISOLATION](https://github.com/M7MMAD-OMAR/sbarbase/blob/main/docs/engineering/FUNCTIONS-NETWORK-ISOLATION.md)). وترفض شبكة الخروج أي حركة بين حاوياتها.

## الإصدار [0.5.3]، 2026-10-17

### أُضيف

- **Studio من العنوان العام.** يضبط `SBARBASE_STUDIO_HOST` عنوان Studio لكل بيئة بنمط مثل `studio-{id}.example.com`، ويخدمه وكيل TLS بالخيار `--studio-host`. ومع سجل DNS شامل وشهادة تغطيه، تفتح لوحة الإدارة Studio على ذلك العنوان بدل `<id>.studio.localhost` الذي لا يُوصل إليه إلا بنفق SSH ([Studio](https://base.sbarah.com/docs/guides/studio/#فتحه-من-أي-مكان)). وإلى أن يُضبط ذلك، تشرح لوحة الإدارة المفتوحة من عنوانها العام طريقة النفق بدل أن تفتح تبويبًا لا يصل إليه المتصفح.

### الأمان

- لا يخدم وكيل TLS إلا مضيفه العام وأسماء loopback وعناوين Studio المطابقة، ويجيب أي مضيف آخر بـ 421، فلا يُظهر سجل DNS الشامل لوحة الإدارة تحت اسم آخر.
- على العنوان العام، صار ملف تعريف جلسة Studio من نوع `__Host-` و`Secure`، وتذكرة الدخول إلى Studio لا تعمل إلا مرة، والطلب الذي يغيّر شيئًا يجب أن يأتي من صفحة Studio نفسها، ويُرفض الطلب الذي يبدؤه موقع آخر إلا زيارة عادية تصل إلى الصفحة الرئيسية للمشروع دون معاملات رابطها.

### أُصلح

- لم تعد حاويات Studio تظهر غير سليمة وهي تعمل: كان فحص السلامة المدمج في الصورة يسأل عنوانًا لا يستمع عليه Studio.
- استعادت التنبيهات في صفحات Functions وSign-in وDatabase وEnvironments وUpdates شكلها الأصلي، بعد أن غيّره نمط أُضيف في 0.4.0.

## الإصدار [0.5.2]، 2026-10-17

### أُصلح

- الجدول الذي ينشئه وكيل عبر نقطة MCP أو `/v1` كان يُجاب عنه بـ 404 في التطبيق حتى يعيد PostgREST قراءة المخطط بطريقة أخرى. صار الخادم يطلب من PostgREST إعادة القراءة بعد كل ترحيل أو استعلام قد يغيّر البيانات، كما تفعل قاعدة بيانات Supabase. اكتُشف ذلك أثناء نشر حي نفّذه وكيل على الخادم الحقيقي.

## الإصدار [0.5.1]، 2026-10-17

### أُصلح

- **لم تستطع معظم العملاء قراءة رد دالة Edge Function.** كانت البوابة تمرّر ترويسة `Accept-Encoding` الخاصة بالمتصل إلى بيئة تشغيل الدوال، فتضغط ردها؛ ثم تفك البوابة الضغط بنفسها وتُبقي ترويسة `content-encoding: gzip`، ففشل `fetch` وsupabase-js في قراءة الرد. صارت البوابة تطلب من الخدمات ردًا غير مضغوط، ويتولى وكيل TLS أو شبكة التوزيع الضغط للعميل. اكتُشف ذلك أثناء نشر حي نفّذه وكيل على الخادم الحقيقي.
- صار `supabase functions deploy --use-api` ينشر الدالة بالترتيب نفسه الذي تنشر به لوحة الإدارة: تصبح مسارات CLI مثل `supabase/functions/<name>/...` و`supabase/functions/_shared/...` ملفات الدالة نفسها وشيفرتها المشتركة.
- صار اسم رمز الوصول يقبل الأقواس والفاصلة العليا و`@ : / +`.

## الإصدار [0.5.0]، 2026-10-17

### أُضيف

- **صار بإمكان وكلاء الذكاء الاصطناعي النشر على صباربيز.** ينشئ الشخص رمز وصول شخصيًا (`sbp_...`) من صفحة **Access tokens** الجديدة في لوحة الإدارة: لكل ما يصل إليه، أو لمنظمة واحدة، أو لمشروع واحد، للقراءة فقط أو لا، وتنتهي صلاحيته خلال سنة على الأكثر. وبه يتصل وكيل مثل Claude Code أو Cursor أو Codex بـ `https://<console>/mcp`، التي تشغّل خادم MCP الرسمي من Supabase (`@supabase/mcp-server-supabase`). فيستطيع إنشاء المشاريع، وتشغيل SQL والترحيلات، ونشر Edge Functions، وقراءة المفاتيح والسجلات وتنبيهات الأمان ([وكلاء الذكاء الاصطناعي](https://base.sbarah.com/docs/guides/agents/)).
- **واجهة إدارة متوافقة مع Supabase** تحت `/v1`، بالرموز نفسها: المنظمات، والمشاريع (كل بيئة مشروع، بمعرّف من 20 حرفًا)، ومفاتيح API، وSQL، وسجل الترحيلات، وEdge Functions وأسرارها، والسجلات والتنبيهات.
- **مهارة لـ Claude Code** (`deploy/agent-skill/sbarbase/SKILL.md`) تعلّم الوكيل ما يعنيه "انشر على Sbarbase".
- **يمكن نسخ المفاتيح العامة مرة أخرى** من صفحة مفاتيح API، كما في Supabase، لأنها عامة بطبيعتها. ينطبق هذا على المفاتيح المنشأة من هذا الإصدار، ويبقى المفتاح السري محفوظًا ببصمته فقط ويظهر مرة واحدة.

### تغيّر

- صار حساب المطوّر يحفظ سجل الترحيلات في مخطط `supabase_migrations` أُنشئ له، وما زال لا يستطيع إنشاء مخططات. أوقف الوصول إلى قاعدة البيانات ثم شغّله مرة واحدة للبيئة التي كان الوصول فيها مفعّلًا من قبل.

### أُصلح

- كان دليل الوصول إلى قاعدة البيانات يقول إن `supabase db push --db-url` يعمل بحساب المطوّر، ولم يعمل قط: فعبارة `CREATE SCHEMA IF NOT EXISTS` التي يرسلها CLI تحتاج صلاحية لا يملكها الحساب عن قصد. صار الدليل يقول ذلك ويعرض `psql` بديلًا.

## الإصدار [0.4.0]، 2026-10-17

### أُضيف

- **مفاتيح API السرية**، كما في Supabase. من صفحة **API keys** للبيئة، أو بالطلب `POST /management/v1/environments/{id}/keys` مع `{"type":"secret","name":"backend"}`، أنشئ مفتاح `sb_secret_` باسم. يعمل خلف البوابة بصفة `service_role` في REST وإدارة مستخدمي Auth وStorage وRealtime وEdge Functions، ويبقى رمز المستخدم المسجّل دخوله هو المعتمد إن وُجد. ويُرفض في أي طلب يبدو آتيًا من متصفح. ويُحفظ ببصمته فقط ويظهر مرة واحدة كالمفتاح العام، ويُسجَّل إنشاء المفاتيح وإلغاؤها ([مفاتيح API](https://base.sbarah.com/docs/guides/api-keys/)).

## الإصدار [0.3.2]، 2026-10-17

### أُضيف

- **الأمر `sbarbase reset-password <email>`** يضع كلمة مرور جديدة لحساب إدارة من سطر أوامر الخادم، للمشغّل الذي نسي كلمته. تُطلب الكلمة الجديدة مرتين دون أن تظهر؛ وتنتهي كل جلسات اللوحة وStudio لذلك الحساب؛ ويبقى تطبيق المصادقة كما هو؛ ويُسجَّل التغيير ([إعداد المشغّل](https://base.sbarah.com/docs/guides/operator-setup/#نسيت-كلمة-المرور)).

### أُصلح

- كان سجل القدرات ما زال يذكر النسخة 0.2.0 في 0.3.0 و0.3.1، فرفضهما المدقق لعدم تطابق النسخة. صار `lab/release.py prepare` يكتب النسخة فيه أيضًا.

## الإصدار [0.3.1]، 2026-10-17

### أُصلح

- **لم يكن الإصدار 0.3.0 قابلًا للتثبيت عبر قناة التحديث.** صرّح بيانه بترحيلات مخطط Auth وStorage على أنها ترحيلات بيانات، وهذا يُخرج الإصدار من القناة كليًا. وهذه الترحيلات تُكتشف أصلًا من تغيّر التثبيتات وتحتاج تأكيد المشغّل (`attended`)؛ لا يصرّح 0.3.1 بأي منها، وكوده هو كود 0.3.0 نفسه. وإعادة تشغيل قاعدة البيانات مرة واحدة وحد العودة فوق أربع بيئات مذكوران في ملاحظاته.

## الإصدار [0.3.0]، 2026-10-17

الانتقال من 0.2.0 يرحّل مخطط Auth وStorage في كل بيئة، فالعودة تكون باستعادة النسخة الاحتياطية التي تؤخذ قبل الترقية. ويرفع أول تشغيل حد اتصالات قاعدة البيانات ويعيد تشغيلها مرة واحدة. لا شيء هنا يُعلن جاهزًا للإنتاج.

### أُضيف

- **حتى ثماني بيئات لكل تثبيت** (كانت أربعًا). ترفع بيئة التشغيل `max_connections` في PostgreSQL من 100 إلى 200 عند التشغيل، ويُسمح لحاوية قاعدة البيانات بـ320 عملية، وتقبل البوابة 64 طلبًا في الوقت نفسه (8 لكل بيئة). في تجربة اصطناعية لثماني قواعد بيانات بيئات تحت حمل كامل، على قاعدة بيانات بذاكرة 1 GiB ومعالج واحد، بلغت الذاكرة 613 MiB على الأكثر ([الدليل](https://github.com/M7MMAD-OMAR/sbarbase/blob/main/docs/evidence/capacity-drill-2026-10-16.json)، `lab/capacity-drill.sh`). على خادم بأربع أنوية لا تتسع الثماني إلا دون Realtime وEdge Functions. وحذف البيئة ما زال لا يحرّر مكانها.
- **ربط تنبيهات تيليجرام من لوحة الإدارة.** يلصق مالك التثبيت رمز البوت في صفحة التنبيهات الجديدة، فيُتحقق منه مع تيليجرام ويُحفظ على الخادم بصلاحيات 0600 ولا يُعرض بعدها أبدًا، وتُربط المحادثة برابط `/start` يعمل مرة واحدة. يرى المدراء الحالة ولا يغيّرها إلا المالكون، ويُسجَّل كل تغيير، ولا تصل التنبيهات القديمة إلى المحادثة الجديدة. وتعيد خدمة الإرسال قراءة إعدادها، فيسري التغيير دون إعادة تشغيل.
- **تنبيهات لامتلاء القرص وتوقف الخدمات.** أقل من 10% أو 5 GiB متاحة تحذير، وأقل من 5% أو 2 GiB تنبيه حرج؛ وتوقف حاوية قاعدة البيانات أو Storage أو تسجيل دخول الإدارة، أو Auth أو REST أو Realtime لبيئة، خمس دقائق تنبيه حرج. لا يتكرر أيّ منها أكثر من مرة في الساعة.
- **فحص من الخارج** (`deploy/uptime-worker/`): عامل Cloudflare يسأل `/health` كل خمس دقائق، ويرسل رسالة واحدة على تيليجرام بعد فشلين متتاليين، وأخرى عند العودة.
- **عمل مواكبة الإصدارات الأصلية** ([الخطة](https://github.com/M7MMAD-OMAR/sbarbase/blob/main/docs/engineering/plans/2026-10-14-upstream-currency.ar.md)): تتبّع الفرق عن الإصدارات الأصلية؛ ونقل قاعدة البيانات إلى صورة PostgreSQL أخرى بإشراف (`lab/upgrade.py database`)؛ وجعل مجلد قاعدة البيانات حالة محفوظة؛ وإعادة بناء الكتلة كاملة من تشغيل نسخ احتياطي واحد (`lab/cluster_rebuild.py`) وأخذها للاستخدام (`lab/cluster_takeover.py`)؛ وإيقاف الكتابة لكل بيئة؛ ونسخ قاعدة الإدارة واستعادتها؛ وتشغيل قاعدة البيانات وحدها للاستعادة بعد فشل عودة Storage.
- **خدمات أصلية محدّثة:** Auth v2.197.0 وPostgREST v14.18 وStorage v1.83.3 وRealtime v2.144.0 وEdge Runtime v1.77.4 وStudio 2026.10.12 وpostgres-meta v0.100.0. يبقى PostgreSQL على 17.6، والانتقال إلى 17.11 ينتظر تجربته.

### أُصلح

- **لم يعد Studio وpostgres-meta في متناول البيئات الأخرى.** لا يتحقق أيّ منهما ممن يناديه، وكانا على الشبكة المشتركة، حيث تستطيع Edge Functions لبيئة أخرى، أو `pg_net` في قاعدة البيانات، تنفيذ SQL بحساب Studio أثناء الجلسة. صار لكل جلسة شبكة خاصة بها، ويستمع postgres-meta على العنوان المحلي داخل نطاق Studio، ويتحقق كل تشغيل من أن لا شيء يجيب على الشبكة المشتركة.
- **الاستعادة على خادم ثُبّت بقناع 002.** كان مجلد حالة التشغيل يُترك بصلاحيات 775، فترفض كل استعادة سجلها؛ صار كل من ينشئه يجعله 0700.

### جُرّب على الخادم الحقيقي

- الترقية من 0.2.0 بأمر التحديث مع الصور الجديدة، وأكدتها فحوص الصحة.
- استعادة بيئة من نسختها المحلية، واستعادة من النسخة المشفّرة خارج الخادم في Cloudflare R2 وحدها؛ عادت البيانات كما نُسخت تمامًا.
- عزل Studio، فُحص من حاوية على الشبكة المشتركة قبل الإصلاح وبعده.

### ما زال مفتوحًا

- أخذ كتلة مُعاد بناؤها للاستخدام حين لا تجهز بديلتها أبدًا ليس له مخرج (S4)، وجزؤه الرابع غير مقبول بعد.
- لم تُجرَّب بعد الاستعادة على خادم جديد من النسخة الخارجية، ولا الاستعادة المنقطعة، ولا تثبيت كامل تحت حركة حقيقية.
- العودة إلى نسخة أقدم ترفض العمل على البيئات بعد تجاوز أربع.

## الإصدار [0.2.0]، 2026-09-26، والتغييرات حتى 0.3.0

كانت هذه البنود مدرجة على أنها لم تُصدر بعد؛ وهي تغطي 0.2.0 وما دُمج بعد وسمه حتى 0.3.0.

### أُضيف

- خطة أكتوبر لتطوير المنتج وقابلية التشغيل، وطريقة تنفيذ تربط كل نتيجة بالأدلة ونطاقها، وعقد تجريبي لهوية مكان التشغيل الأصلي. تبقى بوابات القبول غير المكتملة مسجلة، ولا يعني نشر الشيفرة قبول الإنتاج.
- تحديث فهارس الوثائق وشرح هيكل المستودع، مع الفصل بين الميزات العاملة والتجارب السابقة والعمل التجريبي الحالي.

- **تغيير أسماء العملاء والمشاريع والبيئات ونقلها وحذفها.** يغيّر المالكون والمديرون الأسماء؛ وينقل المالكون مشروعًا إلى عميل آخر يملكونه، فتُلغى مفاتيح API الخاصة به، ويحذفون ما صار فارغًا. لا تُحذف البيئة إلا إذا لم يكن شيء يعمل فيها أو يتغير؛ فتتوقف مفاتيحها فورًا (تجيب البوابة 401)، وتبقى بياناتها على الخادم. من لوحة الإدارة أو من واجهة الإدارة البرمجية.
- **استعادة نسخة احتياطية على تثبيت جديد.** يعيد `sbarbase relink <runtime> <backup>` إنشاء عميل النسخة ومشروعها وبيئتها بمعرّفاتها الأصلية، دون أي مطابقة بالاسم، ثم يملؤها `sbarbase restore`. لا ينتقل الأعضاء ولا مفاتيح API ولا مفتاح التوقيع؛ ويسجّل المستخدمون الدخول من جديد بكلمات مرورهم القديمة. جُرّب على آلة افتراضية ثانية في 2026-09-25.
- **تغيير مفتاح توقيع البيئة.** يضغط المالكون والمديرون **Rotate signing key** (أو `POST .../signing-key/rotate`)، فيعطي المشرف البيئة سر JWT جديدًا، ويعيد إنشاء Auth وREST الخاصتين بها، ويحدّث مستأجريها في Storage وRealtime، ويعيد تشغيل Edge Functions، وينهي كل الجلسات. وتبقى المفاتيح العامة تعمل. والتغيير الذي يتوقف في منتصفه تكمله المحاولة التالية أو التشغيل التالي. وأيضًا: لم تعد إعادة التشغيل تُسقط الوصول المباشر إلى قاعدة البيانات لبيئة من الحالة المنشورة.
- **نقل مشروع من Supabase بأمر واحد.** يقرأ `lab/import_project.py` مشروع Supabase (سحابيًا، أو مستضافًا ذاتيًا، أو بيئة أخرى) وينسخه إلى بيئة جديدة وفارغة: المخطط `public` بسياساته وصلاحيات المصدر نفسها، والمستخدمين ببصمات كلمات مرورهم، وكل الصفوف، والـbuckets والملفات مع مالكيها، والمشغّلات على `auth.users` و`storage.objects`، ثم يقارن الأعداد قبل أن يعلن النجاح. والخيار `--dry-run` يكتفي بالفحص.
- **نسخ احتياطية مشفّرة خارج الخادم.** يأخذ `lab/offsite.py configure` إعدادات S3 (‏Cloudflare R2 وBackblaze B2 وAWS S3 وMinIO) وعبارة مرور من stdin؛ ومن بعدها تُشفَّر كل نسخة يومية على الخادم (AES-256-GCM على أجزاء) وتُنسخ إلى الـbucket، ويُحتفظ بأحدث 30 لكل بيئة، ويعيد `fetch` نسخة منها لتستعيدها بـ `backup.py restore`.
- **الوصول المباشر إلى قاعدة البيانات لكل بيئة.** يشغّل المالكون والمديرون حساب مطوّر ويحصلون على سلسلة اتصال PostgreSQL، وكلمة مرورها تظهر مرة واحدة، لاستخدام `psql` و`pg_dump` و`supabase db push --db-url` وPrisma وDrizzle عبر نفق SSH. يعمل الحساب مثل المستخدم `postgres` في مشروع، داخل قاعدة بياناته وحدها، ومن ذلك المشغّلات على `auth.users` وسياسات Storage، لكنه ليس مستخدمًا خارقًا. ولا يمرّر منفذ loopback (المنفذ 6543) إلا حسابات المطوّرين إلى قواعد بياناتهم نفسها.
- **Edge Functions لكل بيئة.** انشر مجلد `supabase/functions` من مشروع Supabase بأمر واحد (`lab/functions-deploy.ts`)، ومعه `_shared` و`verify_jwt` في `config.toml`، أو اكتب دالة في لوحة الإدارة. كل بيئة تنشر دالة تحصل على edge-runtime أصلي مثبّت الإصدار خاص بها؛ وتُستدعى الدوال عبر البوابة بـ `supabase.functions.invoke()`، وتحصل على `SUPABASE_URL` ومفتاحي anon وservice role لبيئتها، وتقرأ الأسرار المضبوطة في اللوحة، وتصل إلى الإنترنت لاستيرادات `npm:`، ويمكنها استقبال خطافات ويب دون مفتاح عندما يكون `verify_jwt` مطفأً.
- **رفع ملفات حتى 50 MiB، أو الحد الذي تختاره.** يمر رفع الملفات إلى Storage عبر البوابة ووكيل TLS كما يصل، بدل أن يتوقف عند 1 MiB. يضبط `SBARBASE_UPLOAD_LIMIT_MB` (50 افتراضيًا، كما في Supabase) الحد للبوابة والوكيل وStorage معًا، ويُطبَّق أي تغيير عند التشغيل التالي بإعادة إنشاء حاوية Storage المشتركة. تبقى أجسام الطلبات الأخرى عند 1 MiB.
- **السجلات والمقاييس لكل بيئة.** يرى كل عضو في صفحة البيئة آخر ساعة من الطلبات عبر البوابة: المجاميع، وأخطاء العميل والخادم، والوسيط والنسبة 95 لزمن الاستجابة، والطلبات في كل دقيقة ولكل خدمة، واستهلاك خدماتها الخاصة للذاكرة والمعالج. ويقرأ المالكون والمديرون أيضًا آخر الطلبات وسجلات Auth وREST وStorage وRealtime، مع إخفاء المفاتيح والرموز وكلمات المرور قبل أن يخرج أي سطر من الخادم. العدّ في الذاكرة ويبدأ من جديد بعد إعادة التشغيل.
- **Realtime لكل بيئة.** يشغّل المالكون والمديرون Realtime لبيئة من لوحة الإدارة؛ فيعمل Realtime الأصلي مثبّت الإصدار لتلك البيئة وحدها، بحساب دخول خاص بها، ويتوقف عند إطفائه. يعمل البث والحضور وتغييرات قاعدة البيانات في supabase-js (كل جداول `public`، مصفّاة بأمان الصفوف) عبر البوابة، التي تفحص المفتاح قبل أن يصل أي اتصال إلى Realtime. لا يحمل حساب الدخول صلاحيات المدير إلا أثناء إنشاء Realtime لمخططه، في أول تشغيل وبعد الترقية.
- **إعدادات تسجيل الدخول ومزوّدو OAuth لكل بيئة.** يضبط المالكون والمديرون من اللوحة عنوان الموقع، وعناوين إعادة التوجيه المسموح بها، وإنشاء الحسابات والدخول المجهول، وأيًا من 19 مزوّدًا (Google وGitHub وApple وغيرها). الحفظ يعيد إنشاء Auth تلك البيئة وحدها، ويُبقي السابق إذا لم يعمل الجديد. تصل روابط البريد وخطوات OAuth إلى Auth دون مفتاح، كما في Supabase. يحدد `SBARBASE_PUBLIC_URL` العنوان الذي تستخدمه الروابط وعناوين العودة.
- **الوصول من المتصفح.** تستطيع صفحة على أي نطاق استدعاء Auth وREST وStorage عبر البوابة، كما في Supabase: كل رد يحمل `Access-Control-Allow-Origin: *`، وطلب التحقق المسبق يأخذ 204 دون مفتاح، ولا يوجد وضع لبيانات الاعتماد. يبقى دخول المشغّل مقصورًا على نطاق اللوحة نفسها.
- **ترقيات مع عودة تلقائية.** يتحقق `lab/upgrade.py start` من الإصدار الجديد، ويسحب صوره، ويأخذ نسخة احتياطية من كل بيئة، ثم ينقل نسخة المستودع. إعادة التشغيل تستبدل فقط حاويات Auth وREST وStorage التي تغيّر تثبيتها أو إعدادها. إذا فشل ذلك التشغيل، يعود المشرف وحده إلى الإصدار السابق. يُرفض أي إصدار يغيّر صورة PostgreSQL. يرقّي CI ‏PostgREST من v14.15 إلى v14.16، ثم يعود من إصدار معطوب، على جهاز نظيف.
- **الحصة العادلة في البوابة.** لكل بيئة 8 طلبات مضمونة في الوقت نفسه، ويمكن للمزدحمة أن تستعير الأماكن الفارغة حتى 24 من 32، مع إبقاء الحصة غير المستخدمة لكل بيئة نشطة في الدقيقة الأخيرة فارغة (8 أماكن على الأقل). فُحصت عبر HTTP محلي (`docs/evidence/fair-share-checks.json`)، لا مع Supabase ولا تحت حمل مستمر.
- **تنبيه التشبّع.** إذا بقيت بيئة 15 دقيقة متتالية تُرفض عند حدها، أو تزاحم جارة لها، يصل المشغّل تنبيه واحد من نوع `environment.saturated`. الاستعارة وحدها لا تُطلقه أبدًا.
- **تيليجرام** قناة تنبيه ثالثة بجانب البريد وخطاف الويب.
- **الدعوات.** يدعو المالكون والمديرون شخصًا ببريده ودوره، وتعرض لوحة الإدارة رابطًا يُستعمل مرة واحدة ويصلح 7 أيام. يختار المدعو كلمة مرور وينضم، أو يسجّل الدخول أولًا إن كان له حساب. مختبرة بخدمة دخول وهمية، ولم تُجرَّب بعد مع الخدمة الحقيقية.
- **أدوار الأعضاء في لوحة الإدارة.** يغيّر المالك دور عضو أو يزيله، وينتهي وصوله من الطلب التالي. لا يُزال المالك الأخير.
- **النشاط.** يرى المالكون والمديرون ما حدث في منظمتهم، الأحدث أولًا، في لوحة الإدارة (`GET /organizations/{id}/audit`). المشروع المنقول من عميل آخر لا يظهر منه إلا ما حدث بعد وصوله.
- **حصة بوابة لكل بيئة.** تعرض صفحة البيئة في لوحة الإدارة حصتها المضمونة. يرفعها مشغّلو التثبيت أو يخفضونها ويرون ما وُزّع من البوابة كلها، أما منظمة العميل فترى حصتها وحدها. تطبّق البوابة التغيير من الطلب التالي، ويُرفض الرفع الذي يتجاوز الـ32 التي تملكها البوابة.
- **Supabase Studio لكل بيئة.** يشغّل مالكو العميل ومديروه Studio وpostgres-meta الأصليين مثبّتي الإصدار لبيئة واحدة من لوحة الإدارة، ويفتحونه على عنوانه الخاص من خلف تسجيل الدخول إلى اللوحة، ثم يوقفونه. يدخل Studio إلى قاعدة البيانات بحساب يُنشأ مع كل تشغيل، ليس مستخدمًا خارقًا، ولا يوجد إلا أثناء عمله. يستخدم CI عبره الجداول وSQL والمستخدمين والحاويات على جهاز نظيف.
- **تجربة كاملة على خادم فارغ في آلة افتراضية محلية.** يشغّل `lab/vm-rehearsal.sh` آلة Fedora 44 Cloud افتراضية مؤقتة، ويثبّت من نسخة نظيفة من المستودع بأمر القبول الواحد، وينشئ أول مشروع، ثم يعيد التشغيل. نجحت على 4 vCPU و6 GiB (`docs/evidence/vm-empty-server-rehearsal.json`). ليست خادمًا حقيقيًا.
- **فحص المشروع الأول.** الملف `lab/first-project-check.ts`، والخيار `--first-project` في `deploy/server-acceptance.sh`: تسجيل الدخول، والمشروع، والبيئة، والمفتاح، وAuth وREST وStorage عبر البوابة باستخدام supabase-js، ورفض مفتاح ملغى.
- المتغير `SBARBASE_CONSOLE_PORT` يثبّت منفذ لوحة الإدارة على الحلقة المحلية ليستخدمه وكيل TLS.
- تكامل مستمر (CI) لمجموعات اختبارات الوحدات، مع مهمة قبول يدوية على خادم فارغ. تعمل مجموعة Python أيضًا مع عنوان Docker لا يمكن الوصول إليه، فيفشل في المراجعة أي اختبار وحدة يحتاج خدمة Docker.
- **فحص الاستيراد (المرحلة 0).** يقرأ `lab/import_inspect.py` مصدر Supabase للقراءة فقط، ويذكر ما سيرفضه الاستيراد أو يحذّر منه أو يتركه للعمل اليدوي (`docs/evidence/import-inspect-checks.json`). الاستيراد نفسه غير موجود بعد.
- واجهة الإدارة: إنشاء منظمة (لمالكي ومديري منظمة الإعداد الأولي)، وعرض أعضاء منظمة، وإعادة محاولة بيئة فشلت أو أُلغيت. وللوحة الإدارة شاشات مقابلة.
- يسجّل فهرس التحكم إصدار مخططه، ويرفض فهرسًا كتبه إصدار أحدث.
- يسجّل تصدير الاستعادة المنظمة المالكة والمشروع والبيئة.
- أُعيد تنظيم الوثائق في شروح وأدلة ومراجع وقرارات، مع رسوم مرسومة باليد، ودليل بدء سريع، ودليل للخادم، و`SECURITY.md`، ونموذج تهديد، و`CONTRIBUTING.md`، وخارطة طريق.

- **ترحيل جيل الحاوية.** يستبدل `lab/migrate-generation.py` حاوية قاعدة بيانات مُدارة على وحدة تخزين البيانات نفسها، بسجل نية يُثبَّت على القرص بـfsync، ونقطة تحقق لكل مرحلة، وخيار `--reconcile` صريح. نجحت خمس نقاط انهيار بـSIGKILL على البيئة الثابتة المؤقتة (`docs/evidence/fresh-worker-generation-crash-all.json`). يرفض الأمر مكان التشغيل المحفوظ: ذلك التشغيل خطوة مقصودة بحضور المشغّل ولم تحدث بعد، لذا يبقى `lab/durable-check.ts` معطّلًا ويبقى قياسا الحمل المحجوبان محجوبين.

### أُصلح

- ما كشفته تجارب المراحل في الآلة الافتراضية في 2026-09-25: كان قبول الدعوة يرجع 500، لأن طلبات إنشاء الحساب كانت تذهب إلى `/auth/v1/...` على خدمة Auth الإدارة نفسها، وهي تخدمها من جذرها. ورُفضت أول ترقية بعد فحص الاستلام بحجة وجود تعديلات محلية، لأن الفحص يكتب فوق ملفات أدلة متتبَّعة (صارت تُنسخ جانبًا إلى `.lab/upgrades/`). وكان فحص الاستلام ينتظر لوحة الإدارة فور تثبيت الوحدة، قبل وجود الصور، فينتهي وقته دائمًا على خادم فارغ (صارت الوحدة تبدأ بعد التثبيت). وكان سحب الصورة يستسلم بعد إعادة محاولة واحدة فورية (صارت أربع محاولات، بانتظار 15 ثم 45 ثم 90 ثانية).
- كان النسخ الاحتياطي يعدّ الصفوف قبل تشغيل `pg_dump`، فإذا سُجّل مستخدم بينهما دخل صفه في النسخة دون أن يُحسب في البيان، فترفض الاستعادة النسخة. صار العدّ والنسخ يقرآن لقطة واحدة.
- كان المستمع المحلي يعلن `connection: close` بعد رفض طلب لكنه يُبقي الاتصال مفتوحًا، فيعيد العميل استخدامه، ثم يقطع تنظيف بعد ثانية واحدة الطلب الطويل التالي عليه. صار تشغيل الطلبات المستمرة ينجح.
- ما كشفته التجربة الكاملة على الخادم الفارغ: كان القبول يفحص لوحة الإدارة قبل بنائها. وكانت حدود الإدخال والإخراج تسمّي قسمًا من القرص، والنواة ترفض ذلك، فلم تكن قاعدة البيانات تبدأ أبدًا على تقسيم القرص المعتاد في خوادم VPS. وكانت طلبات POST وDELETE التي بلا جسم تصل بجسم عبر منفذ الاستماع الحقيقي، فأجاب إصدار المفاتيح وإلغاؤها بـ400. وكان سحب الصور يعمل بمهلة 600 ثانية دون أي عرض للتقدم. وكان الفشل في أول تشغيل يُعرض كأنه مصدر محفوظ ينتظر التبنّي.
- كان مالك أو مدير أي منظمة يستطيع قراءة تنبيهات كل المنظمات، بمعرّفاتها وأسباب فشلها. صار كل مستدعٍ يرى أحداث منظماته وحدها.
- كان CI يفشل على خادم نظام ملفاته الجذر قسم من القرص: اختبار ما زال يتوقع القسم، بينما تسمّي طبقة التشغيل القرص كله، وهذا هو الصحيح.
- خمسة اختبارات وحدة للقبول كانت تستدعي Docker فعلًا وتفشل دون خدمته.
- كان اختبار الاستلام يسجّل الوحدة نشطة في الثانية نفسها التي شغّلها فيها. صار ينتظر بعد كل بدء، 300 ثانية على الأكثر، حتى ترد لوحة الإدارة عبر loopback، وإلا فشل وذكر آخر ما رآه.

### تغيّر

- صار مخطط فهرس التحكم في الإصدار 3: يقبل جدول التسليم قناة تيليجرام. الترحيل باتجاه واحد، فالإصدار الأقدم يرفض فهرسًا فتحه هذا الإصدار.
- صارت بوابة التطبيقات تُعير الأماكن الفارغة بدل رفض كل طلب يتجاوز 8 لكل بيئة، ويبقى فحص الحمل يقيس الحصة الثابتة.
- صار شرط البدء يُشتق من مكان التشغيل الذي يبدؤه الأمر فعلًا (1792 MiB من الحدود على خادم فارغ، و512 MiB لكل بيئة، واحتياطي 2560 MiB)، ويستخدم الفحص المسبق و`ExecStartPre` في الوحدة وطبقة التشغيل حسابًا واحدًا. كان الشرط ثابتًا: 5888 MiB في الفحص المسبق و6 GiB في طبقة التشغيل.
- صارت كل خطوة في GitHub Actions مثبّتة ببصمة إيداع كاملة (commit SHA)، والوسم الذي أُخذت منه مكتوب بجانبها في تعليق، فلا يغيّر نقلُ وسمٍ ما يشغّله CI.
- تُقبل حدود المعالج كسقوف: حتى ضعف عدد الأنوية بعد ترك نواة واحدة للخادم. القاعدة القديمة كانت تطلب 8 أنوية.
- تُرفض البيئة الجديدة إذا كانت إعادة التشغيل التالية لن تستطيع قبولها. وعلى تثبيت نُقلت فيه بيئة، صار هذا الفحص والفحص المسبق يحسبان حاويات هدف الاستعادة الحالي بحساب واحد. كان الفحص يحسب مكان تشغيل المصدر وحده، وصارت ذاكرة الهدف العامل تُحسب مستخدمة بدل أن تُحسب مرتين. أما هدف استعادة لم يجرِ التحويل إليه بعد فلا يحسبه أيّ منهما، لأن البدء التالي لا يشغّله.
- أسماء المشاريع فريدة داخل المنظمة، وأسماء البيئات فريدة داخل المشروع. التعارض يعيد 409 لا 500. وترفض الواجهة بـ409 أي بيئة تتجاوز حد التثبيت قبل وضعها في الطابور.
- نقل مشروع يلغي مهامه المنتظرة في الطابور أثناء النقل، ويوجّه مهامه إلى الوجهة، فتذكر الأحداث اللاحقة المالكين الجدد.

- أداتا الحمل لم تعودا تكتبان فوق أدلتهما عند الفشل، ولا تتركان التنظيف يخفي الخطأ الحقيقي. وصارت أداة SDK تفحص بيئتها الثابتة أولًا.
- لم يعد `NOTICE` يصف Supabase Studio بأنه مُقدَّم، فهو مخطط له.

### ملاحظات

- يوجد في المستودع ملف `LICENSE` (Apache-2.0). يقول مدخل 0.1.0 أدناه إنه لا يوجد ملف ترخيص، وأبقينا ذلك المدخل كما صدر.

## الإصدار [0.1.0]، 2026-09-21

أول محطة موسومة. تحمل عمل المنصة على العزل والمحاسبة، وبريد كل بيئة، وتنبيهات المشغّل، وأدلة القياس التي تقول ما يفعله العزل وما لا يفعله.

### أُضيف

- **فئات الموارد وفصل الإدخال والإخراج على القرص.** تُشغَّل كل حاوية ضمن فئة سياسة لها وزن للمعالج، ووزن للإدخال والإخراج، وحدود لكل جهاز لسرعة القراءة والكتابة وعدد العمليات في الثانية (IOPS). يُستخرج الجهاز من الخادم بدل كتابته يدويًا، ويرفض التشغيل بدل أن يبدأ حاوية بلا فصل للإدخال والإخراج. `lab/resource_policy.py`، `docs/engineering/RESOURCE-POLICY.md`.
- **مكان تشغيل معدود يُستخرج من خدمة Docker.** يقرأ القبول الحاويات التي تنسبها خدمة Docker إلى وسم المالك، بدل قائمة أسماء مكتوبة يدويًا. فالمكوّن الذي لم يُخبر به أحدٌ الوحدةَ يُعدّ مع ذلك، والحاوية الموسومة خارج مكان التشغيل المسجّل سبب للرفض ما دامت تعمل.
- **أخذ عينات مستمر لضغط الخادم واستجابة من المستوى 1.** يأخذ `lab/pressure_admission.py` سلسلة محدودة من القراءات خلال نافذة زمنية ويلخّصها، ويرفض القبول الجديد ما دامت أحدث قراءة عند العتبة أو فوقها، ويضيف كل تجاوز إلى دفتر دائم. كل قرار يذكر، بجانب الإجراء، ما لم يُنفَّذ بعد.
- **بريد كل بيئة.** ملف إعدادات واحد بصلاحية 0600 لكل بيئة، ومتغيرات بيئة لـAuth تُبنى منه، وأمر مطابقة صريح يعيد إنشاء Auth لبيئة واحدة ليطبّق الإعدادات أو يزيلها، وملف حالة غير سري. `lab/mail_config.py`، `lab/mail_state.py`، `docs/engineering/ENVIRONMENT-EMAIL.md`.
- **تنبيهات المشغّل.** صندوق صادر دائم وجداول تسليم تُثبَّت صفوفها داخل المعاملة نفسها التي تسجّل تغيير الحالة الذي تصفه، وتصريف داخل العامل، وقناة بريد، وقناة خطاف ويب موقّع، وبوابة تنقية لبيانات الاعتماد تفشل مغلقة، وأحد عشر نوعًا من الأحداث موصولة عند تغييرات حالتها الدائمة (بدء التثبيت وإيقافه وفشل بدئه، وإعادة تشغيل العامل وبلوغ حد إعادة التشغيل، وتطبيق السياج ورفعه، واكتمال التصدير وفشله، والتحقق من الاستعادة وفشلها). `lab/notify.py`، `lab/notification_producers.py`، `docs/engineering/OPERATOR-NOTIFICATIONS.md`.
- **واجهات في لوحة الإدارة للاثنين.** مسار للقراءة فقط يعرض حالة بريد البيئة، وآخر يعرض عدد التنبيهات غير المسلّمة. تظهر حالة البريد في صفحة البيئة، والعدد في إطار لوحة الإدارة.
- **فحوص حية مؤقتة مع ضوابط سلبية.** فحص بريد يثبت التسليم، ويختبر بيئة غير مُعدّة، وخادم ترحيل معطّلًا، وبيانات اعتماد خاطئة. وفحص تنبيهات يثبت التسليم، ومنع التكرار، وبوابة التنقية، وأن القناة المعطّلة تسجّل فشلًا بدل أن تغيّر العملية التي تبلّغ عنها.
- **الوثائق.** ثلاثة سجلات تصميم، ومراجعة نقدية تحدد معايير قبول لا يمكن تزييفها، وخطة تنفيذ، وخطة لترحيل جيل الحاوية المؤجل، وأدلة القياس في `docs/evidence/`.
- عرض Studio الأصلي لكل بيئة على مسار الإدارة، وصارت لوحة الإدارة تتبع سمة نظام التشغيل افتراضيًا.

### تغيّر

- صار حساب مكان التشغيل مشتقًا بدل أن يكون قائمة، وصفوف الإدخال والإخراج هي الآلية التي تفرض الحد فعلًا، لأن القياس أظهر أن عمود الوزن لا يفرضه.
- أُزيل جدول الفهرس `environment_mail` الذي لم يكتب فيه أحد، واستُعيض عنه بملف الملخص الذي تكتبه طبقة التشغيل نفسها، وهو المصدر الوحيد الذي تقرؤه لوحة الإدارة.
- صارت مقارنة إعدادات البريد تجري في الاتجاهين، فلا يبقى في حاوية معاد استخدامها مفتاح لم يعد في الإعدادات المطلوبة.

### أُصلح

- البريد: كان مسار "بلا تغيير" يسجّل حالة لا يعرّفها المعجم، فكان التشغيل الثاني على إعدادات لم تتغير يرمي خطأ بدل أن يبلّغ. صار اختبار على مستوى المصدر يمر على كل موضع يُستدعى فيه التسجيل ويشترط حالة معرّفة.
- البريد: كانت الإعدادات التي حذفها المشغّل قد تنجو من إعادة التشغيل، وتُبقي في الحاوية المعاد استخدامها بيانات اعتماد SMTP حية وحدود المعدل وفترة تهدئة خادم الترحيل.
- التنبيهات: كانت نافذة التصعيد هي نافذة الخطورة نفسها، فكانت القناة المعطّلة ستُصعّد نحو 72 مرة كل ست ساعات بدل مرة واحدة، وكان يمكن لقناتين معطّلتين أن تصعّد كل منهما الأخرى.
- مكان التشغيل: كانت حاوية مملوكة خارج مكان التشغيل المسجّل ترفض بدء التثبيت، بينما كانت المراجعة السابقة تقبلها. وكانت حاوية موسومة تحت أي مالك آخر تفلت من العدّ، مع أن وثائق الوحدة نفسها كانت تزعم أنها معدودة.
- مكان التشغيل: صار كل موضع ينشئ هدف استعادة يحمل وسم فئته، والحارس الذي كان يزعم أن كل موضع تشغيل يمرّر فئة صار حدًا أدنى، لا عدًّا دقيقًا ينكسر عند إضافة موضع تشغيل جديد.
- فحص التنبيهات: صار تشغيله الافتراضي يختبر بوابة التنقية التي تفشل مغلقة، ولم يكن يفعل. ولم تعد مقارنة الملخص فيه تعيد قراءة جملة وقت العرض التي كانت تجعل أحد الفحوص رمية عملة.
- البريد: يُرفض الرابط الرمزي المعلّق بدل أن يُقرأ بصمت كأن البيئة غير مُعدّة.

### ما قيس، مع أدلته في المستودع

- الملف `docs/evidence/resource-policy-cgroup-mapping.json`: يتحوّل `--cpu-shares` إلى `cpu.weight` في cgroup v2 بعلاقة أقل من الخطية (القيمة 2048 تعطي 174 لا 800)، ولم يفرض `--blkio-weight` شيئًا على هذا الخادم، بينما فرض `--device-write-bps` الحد، ووضع قيمة `wbps` رقمية في `io.max`.
- الملف `docs/evidence/noisy-neighbor-sql-runs.json`: خمسة تشغيلات لتجربة الجار المزعج، حُفظ منها ثلاثة. لا أثر قابل للتكرار: الوسيط والشريحة p95 والحد الأقصى تبقى ثابتة بين خط الأساس والمرحلة التي تشبع فيها بيئة ثانية المحرك المشترك. أظهر تشغيل سابق قفزة في الذيل لم تكررها أربعة تشغيلات لاحقة، فسُجّلت كقيمة شاذة لا كثمن للجار المزعج.
- الملف `docs/evidence/pressure-response-checks.json`: تجاوز حقيقي للعتبة على حاوية مؤقتة، ورفض المستوى 1، وسطر واحد في الدفتر الدائم، وعودة إلى القبول بعد التعافي.
- الملف `docs/evidence/auth-templates-source-v2.196.0.json`: ما يفعله متغير القالب في إصدار Auth المثبّت، مقروءًا من مصدر الوسم نفسه مع بصمة لكل ملف. قيمة القالب عنوان HTTP، وليست ملفًا أبدًا.
- فحوص حية أعاد المشرف تشغيلها على الشجرة المدمجة: البريد 36 فحصًا، والتنبيهات 21 فحصًا، وكلاهما ينظّف ما أنشأه. البوابات: 575 اختبار Python، و87 اختبار Bun، وفحص أنواع الواجهة، وفحص بناء لوحة الإدارة.

### ليس في هذا الإصدار

نذكره هنا بدل أن يُكتشف لاحقًا:

- **لا تجربة كاملة على خادم.** مصفوفة جاهزية النشر منفّذة ومثبتة على محطة عمل، وليست تجربة على عتاد حقيقي.
- **ترحيل جيل الحاوية مؤجل**، فلا يمكن إعادة إنشاء حاوية قاعدة بيانات محفوظة. لذلك ينطبق عقد الفئات على أماكن التشغيل التي تُنشأ بعده، ويبقى مكان التشغيل المحفوظ على جهاز التطوير مستثنى. الخطة في `docs/engineering/CONTAINER-GENERATION-MIGRATION.md`.
- **قياسان محجوبان، لا مجرد أنهما لم يُشغَّلا**: تجربة الضغط المدفوعة بتوالي الطلبات، وحمل SDK المختلط. مولّد بيئتهما الثابتة الوحيد، `lab/durable-check.ts`، معطّل حتى ذلك الترحيل، وبيئته الثابتة على جهاز التطوير تشير إلى بيئة متقاعدة. وإحدى أداتي الحمل تكتب فوق أدلتها حين تفشل، وتنظيفها يخفي الخطأ الحقيقي.
- **جداول الفئات غير معايَرة.** صفوف الإدخال والإخراج تفرض الحد وتفصل الفئات، ولم تقس أي تجربة ما تحصل عليه الفئة تحت الحمل.
- **ثلاثة أنواع من التنبيهات لا يطلقها أحد**: الضغط، ورفض طبقة التشغيل، وتغيّر الهامش. ولا شيء يستدعي استجابة الضغط وفق جدول زمني.
- **البريد للقراءة فقط في لوحة الإدارة**، وما زال المشغّل يختار مزود SMTP بنفسه. القوالب هي الافتراضية في الأصل، والقالب البديل يجب أن يُخدم من داخل شبكة التشغيل الداخلية.
- **لا ملف ترخيص.** يذكر `NOTICE` حقوق النشر ونسبة الأعمال إلى أصولها، ومنها أن Supabase Studio وpostgres-meta مستخدمان كصور مثبّتة الإصدار دون تعديل، وأن لوحة الإدارة عمل صباربيز الخاص. اختيار الترخيص قرار المشرف، ولم يُتخذ هنا.
